Groupby 并根据条件将多个组合并聚合为一个组

Groupby and combine and aggregate multiple groups into one single group based on condition

我有一个涉及多个顶级实体的分层时间序列 pandas DataFrame。我想合并和聚合少于 12 个数据点的系列(即 date 的计数少于 12)。将它们组合起来,这样我就可以拥有超过 12 个数据点,并聚合出现在相同 date.

上的值

请注意,我不想合并属于不同 level0 组的那些,因为它们不相关(例如,A 和 Z 是两个不同的实体)。换句话说,我想对每个 level0 组内的 level2 进行组合和聚合。 groupby之后的原始数据集是这样的:

grp = df.groupby(['level0','level1','level2','date']).sum() #sum the values within the same date
                                                            #because each level2 entity can have multiple records occurring on the same date

                                        values
level0  level1  level2      date        
A       AA      AA_1        2006-10-31  300 # assume AA_1 have more than 12 data points so I dont't want to modify
                            2006-11-30  220
                            2006-12-31  415
                            ...         ...
                            2007-04-30  19
                            2007-05-31  77
                            2007-08-31  463
                AA_2        2006-04-30  600 # assume AA_2 has less than 12 data points
                            2006-05-31  2600
                            2007-09-30  6600
        AB      AB_1        2006-04-30  100 # assume AB_1 has less than 12 data points
                            2006-08-31  200
                            2007-06-30  300
                            2007-09-30  400
...     ...     ...         ...         ...
Z       ZZ      ZZ_9        2006-04-30  3680 # assume ZZ_9 has less than 12 data points
                            2006-09-30  277
                            2007-03-31  1490
                            2007-09-30  289
                            2007-10-31  387

我假设属于 A 组的 AA_2AB_1 都少于 12 个数据点,所以我想将它们合并。他们有两个重复的日期,所以对于这两个日期,我想总结价值。得到新的层级组后,我也想把原来的去掉。

虽然ZZ_9也有不到12个数据点,但我不会将其与其他两个合并,因为ZZ_9属于组Z

期望的输出是这样的:

                                            values
level0  level1      level2      date        
A       AA          AA_1        2006-10-31  300
                                2006-11-30  220
                                2006-12-31  415
                                ...         ...
                                2007-04-30  19
                                2007-05-31  77
                                2007-08-31  463
        agg_lv1     agg_lv2     2006-04-30  700 (=600+100) # assume we have more than 12 data points now
                                                           # as I don't want the code being lengthy
                                2006-05-31  2600
                                2006-08-31  200
                                ...         ...
                                2007-06-30  300
                                2007-09-30  7000 (=6600+400)
...     ...         ...         ...         ...
Z       ZZ          ZZ_9        2006-04-30  3680
                                2006-09-30  277
                                2007-03-31  1490
                                2007-09-30  289
                                2007-10-31  387

每个 level0 实体对于新的聚合级别(即 agg_lv1agg_lv2)具有相同的名称没关系,因为如上所述 level0 实体是不相关的我想保持命名简单。

如何做到这一点?

您可以分多个步骤完成此操作。首先将数据帧分成 2 个,其中第一个包含需要聚合的所有行(超过 12 个时间点和超过一个 level1 组)。

grp = grp.reset_index()
grp['nunique'] = grp.groupby(['level0'])['level1'].transform('nunique')

# partition
grp_small = grp.loc[grp['nunique'] > 1].groupby(['level0', 'level1', 'level2']).filter(lambda x: len(x) < 12)
idx_small = grp_small.index
grp_large = grp.loc[set(grp.index) - set(idx_small)]

现在我们可以在 grp_small 数据帧上应用 sum 聚合,同时保持 grp_large 不变。

grp_small = grp_small.groupby(['level0', 'date'], as_index=False).sum()
grp_small[['level1', 'level2']] = ['agg_lv1', 'agg_lv2']

最后,我们将两个数据帧连接在一起并应用一些最终的后处理:

df = pd.concat([grp_large, grp_small], ignore_index=True)
df = df.drop(columns='nunique').set_index(['level0', 'level1', 'level2', 'date']).sort_index()

给定数据的结果(在计算过程中向第一组添加了行):

                                   values
level0 level1  level2  date              
A      AA      AA_1    2006-10-31     300
                       2006-11-30     220
                       2006-12-31     415
                       ...            ...
                       2007-04-30      19
                       2007-05-31      77
                       2007-08-31     463
       agg_lv1 agg_lv2 2006-04-30     700
                       2006-05-31    2600
                       2006-08-31     200
                       2007-06-30     300
                       2007-09-30    7000
...   ...       ...           ...     ...
Z      ZZ      ZZ_9    2006-04-30    3680
                       2006-09-30     277
                       2007-03-31    1490
                       2007-09-30     289
                       2007-10-31     387