借助自定义功能轻松实现

时间:2020-03-16 19:07:41

标签: python-3.x pandas dask

我正在尝试使用Dask,但是在分组后使用apply时遇到了问题。

我有一个Dask DataFrame,其中包含大量行。让我们考虑下面的例子

N=10000
df = pd.DataFrame({'col_1':np.random.random(N), 'col_2': np.random.random(N) })
ddf = dd.from_pandas(df, npartitions=8)

我想对col_1的值进行装箱,并遵循here的解决方案

bins = np.linspace(0,1,11)
labels = list(range(len(bins)-1))
ddf2 = ddf.map_partitions(test_f, 'col_1',bins,labels)

其中

def test_f(df,col,bins,labels):
    return df.assign(bin_num = pd.cut(df[col],bins,labels=labels))

这和我预期的一样。

现在,我想取每个bin中的中值(取自here

median = ddf2.groupby('bin_num')['col_1'].apply(pd.Series.median).compute()

我有10个存储箱,我希望median有10行,但实际上有80行。数据帧有8个分区,所以我猜想应用程序在某种程度上可以单独工作。

但是,如果我想要平均值并使用mean

median = ddf2.groupby('bin_num')['col_1'].mean().compute()

它有效,输出有10行。

然后的问题是:我在做错什么,阻止apply用作mean

2 个答案:

答案 0 :(得分:2)

也许这个警告是关键(Dask doc: SeriesGroupBy.apply):

Pandas的groupby-apply可用于应用任意功能,包括导致每组一行一行的聚合。 Dask的groupby-apply 将对每个分区组对应用一次func ,因此,当func减少时,您将在每个分区组对中得到一行。要对Dask应用自定义聚合,请使用dask.dataframe.groupby.Aggregation。

答案 1 :(得分:1)

您是对的!我能够在Dask 2.11.0上重现您的问题。好消息是,有解决方案!看来Dask groupby问题专门与类别类型(pandas.core.dtypes.dtypes.CategoricalDtype)有关。通过将类别列转换为其他列类型(float,int,str),groupby将可以正常工作。

这是我复制的代码:

import dask.dataframe as dd
import pandas as pd
import numpy as np


def test_f(df, col, bins, labels):
    return df.assign(bin_num=pd.cut(df[col], bins, labels=labels))

N = 10000
df = pd.DataFrame({'col_1': np.random.random(N), 'col_2': np.random.random(N)})
ddf = dd.from_pandas(df, npartitions=8)

bins = np.linspace(0,1,11)
labels = list(range(len(bins)-1))
ddf2 = ddf.map_partitions(test_f, 'col_1', bins, labels)

print(ddf2.groupby('bin_num')['col_1'].apply(pd.Series.median).compute())

打印出您提到的问题

bin_num
0         NaN
1         NaN
2         NaN
3         NaN
4         NaN
       ...   
5    0.550844
6    0.651036
7    0.751220
8         NaN
9         NaN
Name: col_1, Length: 80, dtype: float64

这是我的解决方法:

ddf3 = ddf2.copy()
ddf3["bin_num"] = ddf3["bin_num"].astype("int")

print(ddf3.groupby('bin_num')['col_1'].apply(pd.Series.median).compute())

其中打印:

bin_num
9    0.951369
2    0.249150
1    0.149563
0    0.049897
3    0.347906
8    0.847819
4    0.449029
5    0.550608
6    0.652778
7    0.749922
Name: col_1, dtype: float64

@MRocklin或@TomAugspurger 您是否可以在新版本中为此创建修复程序?我认为这里有足够的可复制代码。感谢您的辛勤工作。我爱Dask并每天使用它;)