使用子结果聚合多个类别

时间:2017-08-15 08:24:21

标签: python python-3.x aggregate

这似乎是一个简单的问题,但我找不到任何东西 我有数据帧:

df = pd.DataFrame({'x':[1,3,1,3,1,5,1,5],
                   'cat1':['A','A','B','B','A','A','B','B'],
                  'cat2':['A','A','A','A','B','B','B','B']})

    cat1 cat2 x
0   A    A    1
1   A    A    3
2   B    A    1
3   B    A    3
4   A    B    1
5   A    B    5
6   B    B    1
7   B    B    5

cat1和cat 2是某些类别,我想使用一些聚合函数(总和,加权平均值或定义的东西)对它们进行聚合x。显而易见的解决方案,如

res = df.groupby(['cat1','cat2']).sum()

结果

           x
cat1 cat2   
A    A     4
     B     6
B    A     4
     B     6

但我想要的是:

    cat1    cat2    x
0   A       A       4
1   A       B       6
2   A       Any     10
3   B       A       4
4   B       B       6
5   B       Any     10
6   Any     A       8
7   Any     B       12
8   Any     Any     20

一种方法是使用类似的东西:

res2 = df.groupby(['cat1','cat2']).sum().reset_index()
res1a = df.groupby(['cat1']).sum().reset_index()
res1b = df.groupby(['cat2']).sum().reset_index()
res1a['cat2'] = 'any'
res1b['cat1'] = 'any'
res = res1a.append(res1b).append(res2).set_index(['cat1','cat2'])

但是由于我的实际任务涉及大约10个类别,因此为各种类别子集创建单独的组块并将它们全部附加在一起并不方便。我希望有更好的方法去

1 个答案:

答案 0 :(得分:1)

您可以使用unstack进行重塑,使用Any添加新列和新行sum,然后按stack重新整形:

#add `['x']` for Series output
res = df.groupby(['cat1','cat2'])['x'].sum()
print (res)
cat1  cat2
A     A       4
      B       6
B     A       4
      B       6
Name: x, dtype: int64

a = res.unstack()
a['Any'] = a.sum(axis=1)
a.loc['Any'] = a.sum()
print (a)
cat2  A   B  Any
cat1            
A     4   6   10
B     4   6   10
Any   8  12   20

df1 = a.stack()
print (df1)
cat1  cat2
A     A        4
      B        6
      Any     10
B     A        4
      B        6
      Any     10
Any   A        8
      B       12
      Any     20
dtype: int64

编辑:

res2 = df.groupby(['cat1','cat2']).sum()
res1a = df.groupby(['cat1']).sum()
res1b = df.groupby(['cat2']).sum()
res1a = res1a.set_index(pd.Series(['any'] * len(res1a), name='cat2'), append=True)
res1b=res1b.set_index(pd.Series(['any'] * len(res1b), name='cat1'), append=True).swaplevel()
res1ab=pd.DataFrame(res1a.sum().values, 
                   index=pd.MultiIndex.from_arrays([['any'],['any']]),
                   columns=['x'])

res2 = pd.concat([res2, res1a, res1b, res1ab])
print (res2)
            x
cat1 cat2    
A    A      4
     B      6
B    A      4
     B      6
A    any   10
B    any   10
any  A      8
     B     12
     any   20