大熊猫与条件聚合合并

时间:2020-05-28 16:39:48

标签: python pandas merge

我想基于组合键合并两个数据框。考虑到密钥,第二个数据帧具有重复的行。请注意,键在第一个数据帧中也不是唯一的,因为实际数据中实际上还有其他许多列。我需要在第二个数据框上合并聚合(产品)值,但要在日期上附加条件。要聚合的行的日期应比第一个数据帧中的行的日期低。

这里是一个示例:

df1 = pd.DataFrame({
    'Code': ['Code1', 'Code1', 'Code1', 'Code2', 'Code3', 'Code4'],
    'SG': ['SG1', 'SG1', 'SG1', 'SG2', 'SG3', 'SG3'],
    'Date':
    ['2020-02-01', '2020-02-01', '2020-03-01', '2020-01-01', '2020-02-01', '2020-02-01']
})



print(df1)
    Code   SG        Date
0  Code1  SG1  2020-02-01
1  Code1  SG1  2020-02-01
2  Code1  SG1  2020-03-01
3  Code2  SG2  2020-01-01
4  Code3  SG3  2020-02-01
5  Code4  SG3  2020-02-01

df2 = pd.DataFrame({
    'Code': ['Code1', 'Code1', 'Code2', 'Code3'],
    'SG': ['SG1', 'SG1', 'SG2', 'SG3'],
    'Date': ["2019-01-01", "2020-02-25", "2020-01-13", "2020-01-25"],
    'Coef': [0.5, 0.7, 0.3, 0.3]
})

print(df2)

    Code   SG        Date  Coef
0  Code1  SG1  2019-01-01   0.5
1  Code1  SG1  2020-02-25   0.7
2  Code2  SG2  2020-01-13   0.3
3  Code3  SG3  2020-01-25   0.3

我想要以下结果:第二行的总coef为0.5x0.7 = 0.35,因为所有df2.date对应的键的日期都小于df1.Date

    Code   SG        Date  Coef
0  Code1  SG1  2020-02-01  0.50
1  Code1  SG1  2020-02-01  0.50
2  Code1  SG1  2020-03-01  0.35
3  Code2  SG2  2020-01-01   NaN
4  Code3  SG3  2020-02-01  0.30
5  Code4  SG3  2020-02-01   NaN

谢谢您的帮助。

1 个答案:

答案 0 :(得分:1)

好,我终于明白了!

通过代码和SG合并(左加入)

df_group = pd.merge(df1,df2, on=['Code','SG'], how='left', suffixes=('','_result'))

为较低日期创建过滤器

df_group['lower_date_mask'] = df_group['Date_result'] <= df_group['Date']

使用NaN过滤Coef列。

df_group.loc[df_group['lower_date_mask'] == False,'lower_date_mask'] = np.nan
df_group['Coef'] = df_group['Coef'] * df_group['lower_date_mask']

我们在此处为Inte值分配无限值,只是为了避免在使用NaN执行.prod()函数时出现熊猫错误

df_group.loc[df_group['lower_date_mask'] == 1.0,'lower_date_mask'] = np.inf

有关nan的聚合函数的Github问题:https://github.com/pandas-dev/pandas/issues/20824

通过.prod()聚合

df_group = df_group.groupby(['Code','SG','Date']).prod()

创建最终数据框

df_group.reset_index(inplace = True)
df_group.loc[df_group['lower_date_mask'] == 1.0,'Coef'] = np.nan
df_group.drop(columns = ['lower_date_mask'],inplace = True)

最终输出

    Code    SG  Date    Coef
    0   Code1   SG1 2020-02-01  0.50
    1   Code1   SG1 2020-03-01  0.35
    2   Code2   SG2 2020-01-01  NaN
    3   Code3   SG3 2020-02-01  0.30
    4   Code4   SG3 2020-02-01  NaN

值得一说的是,您可以使用.apply()函数来实现此目的,但是,如果DataFrame变大,这会减慢您的速度。

希望我能帮上忙!我花了两个小时才仔细考虑这段代码!

编辑

如@codesensei所述,他的数据库中还有其他列使组合['Code','SG','Date']不唯一。在这种情况下,有两种可能的解决方法。首先,如果df1或df2中还有其他列使组合唯一,则只需将其添加到分组中,如下所示:

df_group = df_group.groupby(['Code','SG','Date','column_of_interest']).prod()

第二,如果更容易通过某种ID将组合设为唯一,例如df1的索引,则可以执行以下操作:

df1.reset_index(inplace = True)
# merge dataframes and follow the other steps as stated earlier in this answer
df_group = df_group.groupby(['Code','SG','Date','index']).prod()

如果需要,可以将“索引”重命名为其他名称,只是为了使其更明确。

希望我能帮上忙!