Dask 设置列 astype 对我不起作用

Dask set column astype not working for me

我无法将 Dask 列转换为特定数据类型。为了简单起见,我将提供单个列 PehRecID - 一列浮点数的详细信息。我已确认所有值都是数字。

以下是我尝试过的内容的总结:

设置数据帧数据类型。我通过了一个 dict 并得到了我预期的结果。当我做 print(df.dtypes) 我得到 {'PehRecID': 'float64', 'PehAccrualCode': 'object', .... 所以我已经成功地设置了数据类型。

使用以下代码将列显式转换为 float64: df['PehRecID'] = df['PehRecID'].astype('float64')

当我尝试 df.to_parquet('foo.parquet', engine='pyarrow') 我得到 ValueError: could not convert string to float: 'PehRecID'

当我尝试 print(df.head()) 我也 get ValueError: could not convert string to float: 'PehRecID'

看来问题出在 Dask,而不是 Parquet。

我正在处理的文件有时对于 Pandas 来说太大了,但并不大。在这种情况下,我实际上是在尝试使用一个相当小的文件来获得正确的基础知识。

使用 dask 时,了解 dask evaluates tasks lazily and asynchronously 很重要,这意味着当您输入命令时,dash 会安排 但不会执行命令 直到需要(因为 writecomputeprinthead 或其他命令需要为该步骤计算结果)。这意味着错误可能会作为一个步骤的结果发生,但您可能要等到稍后执行几个命令后才会发现错误,然后再恢复可能为时已晚。

在您的情况下,df['PehRecID'] = df['PehRecID'].astype('float64') 似乎是罪魁祸首。您在稍后的步骤中收到错误 ValueError: could not convert string to float: 'PehRecID',例如 df.head(),因为您已将带有错误 的命令 的结果分配给数据帧列,使该列不可用。

作为一个非常简单的例子,让我们创建一个包含四个字符串值的 dask 数据帧,其中前三个可以转换为 int,最后一个不能:

In [4]: df = ddf.from_pandas(
   ...:     pd.DataFrame({'A': ['1', '2', '3', 'not a value']}),
   ...:     npartitions=2,
   ...: )
   ...:

In [5]: df
Out[5]:
Dask DataFrame Structure:
                    A
npartitions=2
0              object
2                 ...
3                 ...
Dask Name: from_pandas, 2 tasks

请注意,调用 df.astype(int) 不会引发错误 - 这是因为您只安排了操作 - 您还没有实际执行它:

In [6]: df.astype(int)
Out[6]:
Dask DataFrame Structure:
                   A
npartitions=2
0              int64
2                ...
3                ...
Dask Name: astype, 4 tasks

请注意,dtypes 现在显示 int64,因为这是 .astype(int) 操作的结果指示的数据类型。

计算结果确实引发了预期的错误:

In [7]: df.astype(int).compute()
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-7-05b64497024c> in <module>
----> 1 df.astype(int).compute()
...
ValueError: invalid literal for int() with base 10: 'not a value'

如果就地分配结果,您可能 运行 遇到麻烦:

In [8]: df['A'] = df['A'].astype(int)

同样,数据框的 dtype 已更改以反映 .astype(int) 的预期输出:

In [9]: df.dtypes
Out[9]:
A    int64
dtype: object

效果是现在无法计算df:

In [10]: df.compute()
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-14-9bb416d45ef6> in <module>
----> 1 df.compute()
...
ValueError: invalid literal for int() with base 10: 'not a value'

请注意,如果请求的分区中没有发生错误,则可以屏蔽此问题。在我的例子中,错误发生在第二个分区,所以只使用第一个分区的df.head(),只触发第一个分区的astype(int)操作,不报错:

In [11]: df.head()
/Users/delgadom/miniconda3/envs/rhodium-env/lib/python3.9/site-packages/dask/dataframe/core.py:6383: UserWarning: Insufficient elements for `head`. 5 elements requested, only 2 elements available. Try passing larger `npartitions` to `head`.
  warnings.warn(msg.format(n, len(r)))
Out[11]:
   A
0  1
1  2

如果不完全废弃列或数据帧并重新读取数据,这可能无法从中恢复,因为您已经用未来可靠地生成错误重写了列 A 的内容。

所以我认为您的特定问题的答案是您的数据不干净 - 您的列中某处确实有字符串。