GroupbyRollup或RollDown用于任何类型的聚合
TL;DR:我们如何在 Pandas 中使用任何类型的聚合实现类似于Group By Roll Up 的效果?(本学期感谢@Scott Boston)
我有以下数据框:
P Q R S T
0 PLAC NR F HOL F
1 PLAC NR F NHOL F
2 TRTB NR M NHOL M
3 PLAC NR M NHOL M
4 PLAC NR F NHOL F
5 PLAC R M NHOL M
6 TRTA R F HOL F
7 TRTA NR F HOL F
8 TRTB NR F NHOL F
9 PLAC NR F NHOL F
10 TRTB NR F NHOL F
11 TRTB NR M NHOL M
12 TRTA NR F HOL F
13 PLAC NR F HOL F
14 PLAC R F NHOL F
对于列列表['Q', 'R', 'S', 'T'],我想P在以下 4 个分组列列表上计算列上的一些聚合:
['Q']['Q', 'R']['Q', 'R', 'S']['Q', 'R', 'S', 'T']
我已经写的代码组上述dataframes在越来越多的字段,并且计算聚集(使用count为了简化的抖动)在每个GROUPBY对象,最后将它们连接起来:
cols = list('QRST')
aggCol = 'P'
groupCols = []
result = []
for col in cols:
groupCols.append(col)
result.append(df.groupby(groupCols)[aggCol].agg(count='count').reset_index())
result = pd.concat(result)[groupCols+['count']]
但是,我强烈认为上述方法在 CPU 时间方面效率不高。有没有更有效的方法可以在如此不断增加的列数上应用聚合以进行分组?
为什么我认为它不是那么有效是因为:对于上述值,在第一次迭代中,它对Q列上的数据框进行分组,然后计算聚合。然后在下一次迭代中,它将数据帧分组在Qand 上R,这意味着它再次需要按QthenR对其进行分组,但它已经Q在第一次迭代中分组了,因此重复相同的操作。如果有某种方法可以利用以前创建的组,我认为它会很有效。
输出:
Q R S T count
0 NR NaN NaN NaN 12
1 R NaN NaN NaN 3
0 NR F NaN NaN 9
1 NR M NaN NaN 3
2 R F NaN NaN 2
3 R M NaN NaN 1
0 NR F HOL NaN 4
1 NR F NHOL NaN 5
2 NR M NHOL NaN 3
3 R F HOL NaN 1
4 R F NHOL NaN 1
5 R M NHOL NaN 1
0 NR F HOL F 4
1 NR F NHOL F 5
2 NR M NHOL M 3
3 R F HOL F 1
4 R F NHOL F 1
5 R M NHOL M 1
我已经研究过 Python pandas 中是否有等效的 SQL GROUP BY ROLLUP?和Pandas 数据透视表行小计,它们在我的情况下不起作用,我已经尝试过它们,即这些方法只能用于获取计数,并且当相同的标识符出现多个值时,即使对于唯一计数也会立即失败:
pd.pivot_table(df, aggCol, columns=cols, aggfunc='count', margins=True).T.reset_index()
Q R S T P
0 NR F HOL F 4
1 NR F NHOL F 5
2 NR M NHOL M 3
3 NR All 3
4 R F HOL F 1
5 R F NHOL F 1
6 R M NHOL M 1
7 R All 3
更新
为了避免count在评论中仅根据建议获得任何不必要的混淆,我已将其添加为平均值作为聚合,将P列更改为数字类型:
P Q R S T
0 9 NR F HOL F
1 7 NR F NHOL F
2 3 NR M NHOL M
3 9 NR M NHOL M
4 1 NR F NHOL F
5 0 R M NHOL M
6 1 R F HOL F
7 7 NR F HOL F
8 2 NR F NHOL F
9 2 NR F NHOL F
10 1 NR F NHOL F
11 2 NR M NHOL M
12 3 NR F HOL F
13 6 NR F HOL F
14 0 R F NHOL F
cols = list('QRST')
cols = list('QRST')
aggCol = 'P'
groupCols = []
result = []
for col in cols:
groupCols.append(col)
result.append(df.groupby(groupCols)[aggCol]
.agg(agg=np.mean)
.round(2).reset_index())
result = pd.concat(result)[groupCols+['agg']]
>>> result
Q R S T agg
0 NR NaN NaN NaN 4.33
1 R NaN NaN NaN 0.33
0 NR F NaN NaN 4.22
1 NR M NaN NaN 4.67
2 R F NaN NaN 0.50
3 R M NaN NaN 0.00
0 NR F HOL NaN 6.25
1 NR F NHOL NaN 2.60
2 NR M NHOL NaN 4.67
3 R F HOL NaN 1.00
4 R F NHOL NaN 0.00
5 R M NHOL NaN 0.00
0 NR F HOL F 6.25
1 NR F NHOL F 2.60
2 NR M NHOL M 4.67
3 R F HOL F 1.00
4 R F NHOL F 0.00
5 R M NHOL M 0.00