我正在尝试实现类似df.apply的函数,但是跨数据帧的块并行化。我编写了以下测试代码,以了解我可以获得多少(与数据复制等):
from multiprocessing import Pool
from functools import partial
import pandas as pd
import numpy as np
import time
def df_apply(df, f):
return df.apply(f, axis=1)
def apply_in_parallel(df, f, n=5):
pool = Pool(n)
df_chunks = np.array_split(df, n)
apply_f = partial(df_apply, f=f)
result_list = pool.map(apply_f, df_chunks)
return pd.concat(result_list, axis=0)
def f(x):
return x+1
if __name__ == '__main__':
N = 10^8
df = pd.DataFrame({"a": np.zeros(N), "b": np.zeros(N)})
print "parallel"
t0 = time.time()
r = apply_in_parallel(df, f, n=5)
print time.time() - t0
print "single"
t0 = time.time()
r = df.apply(f, axis=1)
print time.time() - t0
奇怪的行为: 对于N = 10 ^ 7,它可以工作 对于N = 10 ^ 8,它给出了一个错误
Traceback (most recent call last):
File "parallel_apply.py", line 27, in <module>
r = apply_in_parallel(df, f, n=5)
File "parallel_apply.py", line 14, in apply_in_parallel
result_list = pool.map(apply_f, df_chunks)
File "/usr/lib64/python2.7/multiprocessing/pool.py", line 227, in map
return self.map_async(func, iterable, chunksize).get()
File "/usr/lib64/python2.7/multiprocessing/pool.py", line 528, in get
raise self._value
AttributeError: 'numpy.ndarray' object has no attribute 'apply'
有谁知道这里发生了什么? 我也很感激有关这种并行化方式的任何反馈。我期望函数花费的时间比inc或每个行和数百万行的总和还多。
谢谢!
答案 0 :(得分:1)
array_split
接受任何类似数组的参数(包括pandas.DataFrame
个对象),但仅返回保证它返回numpy.ndarray
(哪些DataFrames 不) 。当然,ndarray没有apply
方法,这正是您所看到的错误。我真的很惊讶这适用于任何场景。您需要将数据帧拆分为子帧或应用对ndarrays进行操作的函数。
答案 1 :(得分:1)
N = 10^8
结果2
,N = 10^7
结果13
,因为运营商^
是异或(非权力)。因此,2行长度df不能分成5个块。请改为使用此选项:N = 10**4
和N = 10**5
。使用这些值,您将看到时间差异。小心大于N = 10**6
的值(在此值下,平行时间约为30秒,单次时间约为167秒)。并在pool.close()
的末尾(return
之前)使用apply_in_parallel()
自动关闭池中的所有工作人员。