繁体   English   中英

多处理以在 pandas dataframe 中添加列

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM