我正在尝试使用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
?
答案 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并每天使用它;)