[英]multiprocessing to add a column in a pandas dataframe
我尝试在巨大的 pandas dataframe 中添加新列。 我写了一个 function 来添加新列,现在可以循环遍历 dataframe。 这行得通,但是由于 dataframe 太大了,所以需要很长时间。 所以我尝试使用multiprocessing
模块来加速,但无法让它运行。
下面是一个MWE。 我猜pool.map()
不能直接更改 dataframe ,我需要先将新列保存在其他地方。 注意:在“真实”代码中,我将添加 100 多个新列,这些列也基于其他数据帧中的值(所以我想apply
是不可能的)。
import pandas as pd
import numpy as np
from multiprocessing import Pool
df = pd.DataFrame({"Value1" : [1,2,3], "Value2" : [9,8,7]})
def make_new_columns(i):
df.loc[i, 'mean'] = np.mean([df.loc[i, 'Value1'], df.loc[i, 'Value2']])
df.loc[i, 'sd'] = np.std([df.loc[i, 'Value1'], df.loc[i, 'Value2']])
df.loc[i, 'cv'] = df.loc[i, 'mean'] / df.loc[i, 'sd']
# With a for loop it is working
# for i in range(len(df)):
# make_new_columns(i)
# With multiprocessing it isn't
pool = Pool()
pool.map(make_new_columns, range(len(df)))
感谢您的输入。
编辑:
提供更多背景信息。 我有一个包含网球比赛数据(Match_Table)的data.frame,看起来有点像这样:
匹配表:
Date Player_1 Player_2 Winner Aces_1 Aces_2 [...]
----------------------------------------------------------------------
20200528 Thomas Peter Thomas 6 2
20200526 Peter Michael Peter 8 3
20200524 Donald Bill Bill 3 12
...
现在,我对特定比赛的统计数据很感兴趣。 例如:“例如,彼得在过去 100 场比赛中的胜率是多少?”、“他平均得分多少 ace?”、“他的对手得分多少 ace?”、“他的胜率如何?例如最近 100 场比赛中的比尔?", ...
我还需要过去不同日期的统计数据(例如,2018 年 1 月彼得斯的胜率是多少)。 因此,我用所需的信息(Statistic_Table)制作了第二张表:
统计表:
Date Player1 Player2
----------------------------------------------------------------------
202002 Thomas Peter
202002 Peter Michael
201905 Donald Bill
...
然后我写了一个 function 过滤 Match_Table 并计算 Statistic_Table 的所有缺失列。 我现在可以遍历每一行,因此结果如下:
Date Player Opponent Winrate Winrate_vs avgAces [...]
-------------------------------------------------------------
202002 Thomas Peter 0.47 0.45 4.5
202002 Peter Michael 0.54 0.64 8.4
201905 Donald Bill 0.63 0.78 6.5
...
每件事都很好。 但是由于对于我相当大的 Statistic_Table 中的每个单元格,我必须对另一个表进行子集化并计算统计数据(不仅是平均值或比率,还包括加权平均值等),这需要几个小时。 这是可能的,因为我只需要创建一次表。 但是,如果我可以将工作负载分配到不同的内核上,那么在我必须调整一些参数的情况下,它会更快也更容易。
我还研究了使用某些apply
方法或优化代码的可能性,但由于我(希望)只需要生成表,一旦我不想在这方面浪费太多时间。 因此,尤其是多处理似乎是一个简单的解决方案,因为我可以使用功能强大的计算机。
对于您的用例,有一个比多处理更好的模块。 使用雷。
import pandas as pd
import numpy as np
import ray
ray.init()
@ray.remote
class DataFrameActor:
def __init__(self, df):
self.df = df.copy()
def make_new_columns(self, i):
self.df.loc[i, 'mean'] = np.mean([self.df.loc[i, 'Value1'], self.df.loc[i, 'Value2']])
self.df.loc[i, 'sd'] = np.std([self.df.loc[i, 'Value1'], self.df.loc[i, 'Value2']])
self.df.loc[i, 'cv'] = self.df.loc[i, 'mean'] / self.df.loc[i, 'sd']
def to_df(self):
return self.df
@ray.remote
def worker(_df_actor, value):
_df_actor.make_new_columns.remote(i=value)
df = pd.DataFrame({"Value1" : [1,2,3], "Value2" : [9,8,7]})
df_actor = DataFrameActor.remote(df)
[worker.remote(df_actor, j) for j in range(len(df))]
print(ray.get(df_actor.to_df.remote()))
假设 MWE 中的函数代表您想要在真实框架中执行的操作,您应该按列工作。
df['mean'] = df[['Value1', 'Value2']].mean(axis=1)
df['sd'] = df[['Value1', 'Value2']].std(axis=1)
df['cv'] = df['mean'] / df['sd']
下面是时序代码(其中 df 是用更多行构建的,值是随机绘制的整数)
import pandas as pd
import numpy as np
from multiprocessing import Pool
n_rows = 2000
df = pd.DataFrame({"Value1" : np.random.randint(1, high=100, size=n_rows),
"Value2" : np.random.randint(1, high=100, size=n_rows)})
# Function takes now df as input so no global variables is changed
def make_new_columns(df, i):
df.loc[i, 'mean'] = np.mean([df.loc[i, 'Value1'], df.loc[i, 'Value2']])
df.loc[i, 'sd'] = np.std([df.loc[i, 'Value1'], df.loc[i, 'Value2']])
df.loc[i, 'cv'] = df.loc[i, 'mean'] / df.loc[i, 'sd']
return df
#cellwise construction: 1.98s
%%timeit
df_2 = df.copy()
# With a for loop it is working
for i in range(len(df_2)):
make_new_columns(df_2, i)
# columnwise construction: 2.4**ms**
%%timeit
df_2= df.copy()
df_2['mean'] = df_2[['Value1', 'Value2']].mean(axis=1)
df_2['sd'] = df_2[['Value1', 'Value2']].std(axis=1)
df_2['cv'] = df_2['mean'] / df_2['sd']
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.