我正在尝试对数据框中的每一行进行多行计算。
我当前的解决方案需要近 2 小时才能处理 200k 行。所以效率很低,我希望 groupby 或其他一些 pandas 方法可以在这里帮助我。
例如,我的数据如下所示(您现在可以忽略日期):
id group start_date end_date three_yrs_ago_date days_missing
01 23 2005-01-01 2006-01-01 2002-01-01 1
02 23 2006-01-06 2007-01-06 2003-01-06 6
03 23 2007-01-15 2008-01-15 2004-01-15 9
07 17 2014-01-01 2015-02-01 2011-01-01 2
07 23 2015-01-01 2016-02-01 2012-01-01 4
所以这里的目标是按group
编号对所有内容进行分组,然后将该组中最近 3 年内发生的所有其他行的所有 days_missing
相加年。也就是说,其他行 start_date
位于当前行的 third_yrs_ago_date
或之后,以及当前行的 end_date
或之前。
这有点拗口,但它基本上是三个标准。这样,如果这是整个数据集,我们会得到这个结果(删除日期列):
id group days_missing days_missing_in_last_three_years
01 23 1 1 # no change: no prior years
02 23 6 7
03 23 9 16
07 17 2 2 # no change: only member of it's group
07 23 4 4 # no change: other group members more than 3 years ago
我将向您展示我当前拥有的代码,但速度很慢。
我逐行浏览数据帧,创建一个包含所有组成员的临时数据帧,然后将这些组成员缩减为仅符合日期标准的成员。这并不漂亮:
days=[]
for index, row in tqdm(df.iterrows()):
# moderately slow (~2 hour):
temp = df[df['group'] == row['group']]
temp = temp[temp['start_date'] >= row['three_yrs_ago_date']]
temp = temp[temp['end_date'] <= row['start_date']]
add = temp['days_missing'].sum() + row['days_missing']
days.append(add)
df['days_missing_in_last_three_years'] = days
我尝试了其他两种方法,但都没有成功:
# very slow (~3 hours):
cov.append(df[(df['group'] == row['group']) & (df['start_date'] >= row['three_yrs_ago_date']) & (df['end_date'] <= row['start_date'])]['days_missing'].sum()+row['days_missing'])
# doesn't work - incorrect use of groupby
df['test'] = df[(df.groupby(['group'])['start_date'] >= df.groupby(['group'])['three_yrs_ago_date']) & (df.groupby(['group'])['end_date'] <= df.groupby(['group'])['start_date'])]['days_missing'].sum()
是否有比将其分解为较小的临时数据帧并对其进行计算更有效的更好方法?
最佳答案
这是一种解决方案,可能比您的方法更快。在 df.groupby('group') 上使用循环 for
,然后在每个分组数据报 df_g
上apply
。您可以使用 Between 方法来选择每行两个日期之间的 df_g
部分
for name, df_g in df.groupby('group'):
df.loc[df_g.index,'test'] = df_g.apply(lambda row: (df_g['days_missing'][df_g['start_date']
.between(row['three_yrs_ago_date'], row['end_date'])].sum()),1)
df['test'] = df['test'].astype(int) #to get integer
结果如预期:
id group start_date end_date three_yrs_ago_date days_missing test
0 1 23 2005-01-01 2006-01-01 2002-01-01 1 1
1 2 23 2006-01-06 2007-01-06 2003-01-06 6 7
2 3 23 2007-01-15 2008-01-15 2004-01-15 9 16
3 7 17 2014-01-01 2015-02-01 2011-01-01 2 2
4 7 23 2015-01-01 2016-02-01 2012-01-01 4 4
编辑:使用numpy
函数更快的方法:
import numpy as np
for name, df_g in df.groupby('group'):
m_g = ( np.less_equal.outer(df_g['three_yrs_ago_date'], df_g['start_date'])
& np.greater_equal.outer(df_g['end_date'], df_g['start_date']) )
df.loc[df_g.index,'test'] =np.dot(m_g, df_g['days_missing'])
df['test'] = df['test'].astype(int) #to get integer
关于python - pandas使用groupby加速多行计算,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50935098/