dask dataframe apply meta

时间:2017-06-08 10:13:26

标签: python pandas dask

我想对dask数据帧的单个列进行频率计数。该代码有效,但我得到一个warning抱怨meta未定义。如果我尝试定义meta,我会收到错误AttributeError: 'DataFrame' object has no attribute 'name'。对于这个特定的用例,看起来我不需要定义meta,但我想知道如何做以备将来参考。

虚拟数据帧和列频率

import pandas as pd
from dask import dataframe as dd

df = pd.DataFrame([['Sam', 'Alex', 'David', 'Sarah', 'Alice', 'Sam', 'Anna'],
                   ['Sam', 'David', 'David', 'Alice', 'Sam', 'Alice', 'Sam'],
                   [12, 10, 15, 23, 18, 20, 26]],
                  index=['Column A', 'Column B', 'Column C']).T
dask_df = dd.from_pandas(df)
In [39]: dask_df.head()
Out[39]: 
  Column A Column B Column C
0      Sam      Sam       12
1     Alex    David       10
2    David    David       15
3    Sarah    Alice       23
4    Alice      Sam       18
(dask_df.groupby('Column B')
        .apply(lambda group: len(group))
       ).compute()

UserWarning: `meta` is not specified, inferred from partial data. Please provide `meta` if the result is unexpected.
  Before: .apply(func)
  After:  .apply(func, meta={'x': 'f8', 'y': 'f8'}) for dataframe result
  or:     .apply(func, meta=('x', 'f8'))            for series result
  warnings.warn(msg)
Out[60]: 
Column B
Alice    2
David    2
Sam      3
dtype: int64

尝试定义meta会产生AttributeError

 (dask_df.groupby('Column B')
         .apply(lambda d: len(d), meta={'Column B': 'int'})).compute()

同样的

 (dask_df.groupby('Column B')
         .apply(lambda d: len(d), meta=pd.DataFrame({'Column B': 'int'}))).compute()

如果我尝试将dtype改为int而不是"int",或者'f8'np.float64,那么它似乎不一样导致问题的dtype

关于meta的文档似乎暗示我应该做的正是我正在尝试做的事情(http://dask.pydata.org/en/latest/dataframe-design.html#metadata)。

什么是meta?我该怎么定义呢?

使用python 3.6 dask 0.14.3pandas 0.20.2

1 个答案:

答案 0 :(得分:11)

meta是计算输出的名称/类型的处方。这是必需的,因为apply()足够灵活,可以从数据帧中生成任何内容。正如您所看到的,如果您不提供meta,那么dask实际上会计算部分数据,以查看类型应该是什么 - 这很好,但您应该知道它正在发生。 您可以通过提供输出的零行版本(数据帧或系列)或仅仅类型来避免这种预先计算(这可能是昂贵的)并且当您知道输出应该是什么样时更明确。

计算的输出实际上是一个系列,所以以下是最简单的

(dask_df.groupby('Column B')
     .apply(len, meta=('int'))).compute()

但更准确的是

(dask_df.groupby('Column B')
     .apply(len, meta=pd.Series(dtype='int', name='Column B')))