级联groupby / transform操作

时间:2019-11-14 12:23:41

标签: python pandas

让我们说我有一组带有日期和值的组和子组。

最后,我需要在窗口2中按组逐月评估值的滚动平均值(当前月的值是使用过去2个月来评估的。)

如果我将数据帧减少两个连续的groupby,我可以实现:

  • 第一个评估每个组的值总和(groupby 组|日期,总和)
  • 第二次评估每月滚动平均值 组(groupby group | month,transform,rolling)

但这会减少我的数据。

我需要使用转换操作来完成所有操作,因此我可以将结果作为原始数据帧上的一列来获取。

让我们来看看这个虚拟数据:

values = [100, 100, 200, 200, 300, 300]
dates = ['2017-01-01', '2017-02-01',
         '2018-01-01', '2018-02-01',
         '2019-01-01', '2019-02-01']

df1 = pd.DataFrame({'date': dates, 'value': values})
df1['subgroup'] = 'subgroup1'

df2 = df1.copy()
df2['subgroup'] = 'subgroup2'
df2['value'] = df2.value *2

df_g1 = pd.concat([df1, df2], axis=0)

df_g1['group'] = 'group1'

df_g2 = df_g1.copy()
df_g2['group'] = 'group2'
df_g2['value'] = df_g2.value *2

df = pd.concat([df_g1, df_g2], axis=0)
df['date'] = pd.to_datetime(df.date)

现在进行第一个分组操作:

df_total_by_group = df.groupby(['group', 'date'], as_index=False)[['value']].sum()
df_total_by_group['month'] = df_total_by_group['date'].dt.month

现在滚动平均值:

def rolling_mean(serie):
    return serie.shift(1).rolling(2, min_periods=1).mean()

df_total_by_group['month_rolling_mean_by_group'] = (df_total_by_group
                                                    .groupby(['group', 'month'])['value']
                                                    .transform(rolling_mean)
                                                   )

# display results
df_total_by_group.sort_values(by=['group', 'month'])

enter image description here

我在这里得到正确的结果, 但我需要将它们作为原始数据框中的一列。

我在这里迷路了。有什么建议吗?

2 个答案:

答案 0 :(得分:2)

DataFrame.merge与列列表一起使用-此处缺少on,因为两个数据帧的所有公共列通过相交合并:

df = df.merge(df_total_by_group[['group','date','month_rolling_mean_by_group']], how='left')

所以它的工作方式类似于:

df = df.merge(df_total_by_group[['group','date','month_rolling_mean_by_group']], 
              how='left',
              on=['group','date'])

print (df)
         date  value   subgroup   group  month_rolling_mean_by_group
0  2017-01-01    100  subgroup1  group1                          NaN
1  2017-01-01    200  subgroup2  group1                          NaN
2  2017-02-01    100  subgroup1  group1                          NaN
3  2017-02-01    200  subgroup2  group1                          NaN
4  2018-01-01    200  subgroup1  group1                        300.0
5  2018-01-01    400  subgroup2  group1                        300.0
6  2018-02-01    200  subgroup1  group1                        300.0
7  2018-02-01    400  subgroup2  group1                        300.0
8  2019-01-01    300  subgroup1  group1                        450.0
9  2019-01-01    600  subgroup2  group1                        450.0
10 2019-02-01    300  subgroup1  group1                        450.0
11 2019-02-01    600  subgroup2  group1                        450.0
12 2017-01-01    200  subgroup1  group2                          NaN
13 2017-01-01    400  subgroup2  group2                          NaN
14 2017-02-01    200  subgroup1  group2                          NaN
15 2017-02-01    400  subgroup2  group2                          NaN
16 2018-01-01    400  subgroup1  group2                        600.0
17 2018-01-01    800  subgroup2  group2                        600.0
18 2018-02-01    400  subgroup1  group2                        600.0
19 2018-02-01    800  subgroup2  group2                        600.0
20 2019-01-01    600  subgroup1  group2                        900.0
21 2019-01-01   1200  subgroup2  group2                        900.0
22 2019-02-01    600  subgroup1  group2                        900.0
23 2019-02-01   1200  subgroup2  group2                        900.0

如果将transform用于第一个sum,则其工作方式会不同:

df['value'] = df.groupby(['group', 'date'], as_index=False)['value'].transform('sum')
df['month'] = df['date'].dt.month


def rolling_mean(serie):
    return serie.shift(1).rolling(2, min_periods=1).mean()

df['month_rolling_mean_by_group'] = (df.groupby(['group', 'month'])['value']
                                        .transform(rolling_mean))

print (df)
        date  value   subgroup   group  month  month_rolling_mean_by_group
0 2017-01-01    300  subgroup1  group1      1                          NaN
1 2017-02-01    300  subgroup1  group1      2                          NaN
2 2018-01-01    600  subgroup1  group1      1                        300.0
3 2018-02-01    600  subgroup1  group1      2                        300.0
4 2019-01-01    900  subgroup1  group1      1                        450.0
5 2019-02-01    900  subgroup1  group1      2                        450.0
0 2017-01-01    300  subgroup2  group1      1                        750.0
1 2017-02-01    300  subgroup2  group1      2                        750.0
2 2018-01-01    600  subgroup2  group1      1                        600.0
3 2018-02-01    600  subgroup2  group1      2                        600.0
4 2019-01-01    900  subgroup2  group1      1                        450.0
5 2019-02-01    900  subgroup2  group1      2                        450.0
0 2017-01-01    600  subgroup1  group2      1                          NaN
1 2017-02-01    600  subgroup1  group2      2                          NaN
2 2018-01-01   1200  subgroup1  group2      1                        600.0
3 2018-02-01   1200  subgroup1  group2      2                        600.0
4 2019-01-01   1800  subgroup1  group2      1                        900.0
5 2019-02-01   1800  subgroup1  group2      2                        900.0
0 2017-01-01    600  subgroup2  group2      1                       1500.0
1 2017-02-01    600  subgroup2  group2      2                       1500.0
2 2018-01-01   1200  subgroup2  group2      1                       1200.0
3 2018-02-01   1200  subgroup2  group2      2                       1200.0
4 2019-01-01   1800  subgroup2  group2      1                        900.0
5 2019-02-01   1800  subgroup2  group2      2                        900.0

答案 1 :(得分:1)

我一直在做的事情是为我的聚合创建一个新的数据框架,然后重新加入原始数据框架。

pd.merge(df1, df2, on=['group, 'date'], how='left')