为什么pandas.grouby.mean比并行实现快得多



我在一个非常大的数据集上使用熊猫grouby均值函数,如下所示:

import pandas as pd
df=pd.read_csv("large_dataset.csv")
df.groupby(['variable']).mean() 

看起来这个函数没有使用多处理,因此,我实现了一个并行版本:

import pandas as pd 
from multiprocessing import Pool, cpu_count 
def meanFunc(tmp_name, df_input): 
df_res=df_input.mean().to_frame().transpose()
return df_res 
def applyParallel(dfGrouped, func):
num_process=int(cpu_count())
with Pool(num_process) as p: 
ret_list=p.starmap(func, [[name, group] for name, group in dfGrouped])
return pd.concat(ret_list)
applyParallel(df.groupby(['variable']), meanFunc)

然而,熊猫的实现似乎仍然比我的并行实现快。

我正在查看pandas groupby的源代码,我发现它正在使用cython。这是原因吗?

def _cython_agg_general(self, how, alt=None, numeric_only=True,
min_count=-1):
output = {}
for name, obj in self._iterate_slices():
is_numeric = is_numeric_dtype(obj.dtype)
if numeric_only and not is_numeric:
continue
try:
result, names = self.grouper.aggregate(obj.values, how,
min_count=min_count)
except AssertionError as e:
raise GroupByError(str(e))
output[name] = self._try_cast(result, obj)
if len(output) == 0:
raise DataError('No numeric types to aggregate')
return self._wrap_aggregated_output(output, names)

简短的回答-如果您想对这些类型的情况进行并行处理,请使用dask。你的方法中有陷阱,它可以避免。它可能仍然不会更快,但会给你最好的机会,在很大程度上是熊猫的替代品。

更长的回答

1) 并行性本质上会增加开销,所以理想情况下,并行操作会有些昂贵。把数字加起来并不特别——你说得对,这里使用的是cython,你看到的代码是调度逻辑。实际的核心cython在这里,它可以转化为一个非常简单的c循环。

2) 您使用的是多处理,这意味着每个进程都需要获取数据的副本。这太贵了。通常情况下,由于GIL的原因,您必须在python中执行此操作——您实际上可以(dask也可以)在这里使用线程,因为panda操作是在C中执行的,并释放GIL。

3) 正如@AKX在评论中指出的那样——并行化之前的迭代(... name, group in dfGrouped)也相对昂贵——它为每个组构建新的子数据帧。最初的pandas算法在原地对数据进行迭代。

最新更新