我有一个DataFrame df
:
> df
para0 para1 para2
0 17.439020 True high
1 19.757758 True high
2 12.434424 True medium
3 14.789654 True low
4 14.131464 False high
5 9.900233 True high
6 10.977869 False low
7 8.004251 True medium
8 11.468420 False low
9 12.764453 False high
其中每一行由函数的一组参数组成
foobar
:
def foobar(r):
""" r is a row of df, does something, and it takes a long time"""
if r.para1:
x = r.para2
else:
x = 'low'
return int(r.para0), (r.Index+13)%3 == 0, x
我想将foobar
应用于df
的每一行,收集它
结果,并将这些与他们尊重的参数一起存储在a中,
好吧,DataFrame。
我的(当前)解决方案:
df['count'] = 0
df['valid'] = False
df['outpt'] = ''
def wrapper(r, df):
c, v, o = foobar(r)
df.ix[r.Index,'count'] = c
df.ix[r.Index,'valid'] = v
df.ix[r.Index,'outpt'] = o
for r in df.itertuples():
wrapper(r, df)
这会产生:
> df
para0 para1 para2 count valid outpt
0 17.439020 True high 17.0 False high
1 19.757758 True high 19.0 False high
2 12.434424 True medium 12.0 True medium
3 14.789654 True low 14.0 False low
4 14.131464 False high 14.0 False low
5 9.900233 True high 9.0 True high
6 10.977869 False low 10.0 False low
7 8.004251 True medium 8.0 False medium
8 11.468420 False low 11.0 True low
9 12.764453 False high 12.0 False low
在现实生活中,函数foobar
是
计算成本高,运行大约需要20-30分钟,df
通常有100-2000行。我可以访问一台机器
八个核心,foobar
仅取决于当前处理的行
并且在其他任何事情上,运行这些都应该是微不足道的
并行计算。
当出现问题时(例如,如果有人),这也很好 不小心关闭机器),没有必要启动 从一开始就是一切,即跳过已经存在的行 已经处理完毕。
我该怎么做?
我遗憾地尝试multiprocessing
失败了:
from multiprocessing import Pool
pool = Pool(3)
results = []
for r in df.itertuples():
results += [pool.apply_async(wrapper, r, df)]
使用:
> results[0].get()
…
/usr/lib/python3.5/multiprocessing/reduction.py in dumps(cls, obj, protocol)
48 def dumps(cls, obj, protocol=None):
49 buf = io.BytesIO()
---> 50 cls(buf, protocol).dump(obj)
51 return buf.getbuffer()
52
PicklingError: Can't pickle <class 'pandas.core.frame.Pandas'>: attribute lookup Pandas on pandas.core.frame failed
以下是我创建玩具DataFrame的方法:
import pandas as pd
import numpy as np
df = pd.DataFrame({
'para0' : pd.Series(
np.random.gamma(12,size=10),
dtype=np.float),
'para1' : pd.Series(
[(True,False)[i] for i in np.random.randint(0,2,10)],
dtype=np.bool),
'para2' : pd.Categorical(
[('low','medium','high')[i] for i in np.random.randint(0,3,10)],
ordered=True),
})
答案 0 :(得分:1)
我不知道它是否有帮助,但尝试使用list
代替itertuples
。
我的意思是这样的:
df_list = [[x[0], x[1],x[2]] for x in df.itertuples()]
for r in df_list:
results += [pool.apply_async(wrapper, r, df)]
答案 1 :(得分:1)
如果要将行保留为字典,可以使用to_dict
。这是一个有效的示例(使用starmap
,因为其他参数正在传递给该函数):
from multiprocessing import Pool
import pandas as pd
from itertools import repeat
def test(df_row, otherparam):
print(df_row, otherparam)
return True
if __name__ == '__main__':
df = pd.DataFrame({'a': [0, 1, 2], 'b':[1, 2, 3], 'c':[10, 20, 30]})
df.set_index('a', inplace=True)
pool = Pool(processes=2)
it = df.reset_index().to_dict(orient='records')
results = pool.starmap(test, zip(it, repeat(3)))
print(results)
输出:
{'a': 0, 'b': 1, 'c': 10} 3
{'a': 1, 'b': 2, 'c': 20} 3
{'a': 2, 'b': 3, 'c': 30} 3
[True, True, True]