在熊猫中使用具有多个索引的agg

时间:2020-03-09 16:24:52

标签: pandas multi-index

我在pandas中有一个按列划分的多索引表,如下例所示:

import pandas as pd
header = pd.MultiIndex.from_product([['loc1','loc2'],
                                     ['S1','S2']],
                                    names=['loc','S'])
df = pd.DataFrame(np.random.randint(1, high=5, size=(5,4)), 
                  index=['a','b','c','d','e'], 
                  columns=header)
print(df) 

输出:

loc loc1    loc2   
S     S1 S2   S1 S2
a      4  2    2  5
b      1  4    2  4
c      2  4    2  3
d      3  4    1  2
e      4  1    3  1

我正在尝试对我使用的“ loc1”和“ loc2”执行操作

df.agg({'loc1':sum, 'loc2':np.mean})

但是出现错误: “ SpecificationError:不支持嵌套重命名器”。

预期输出是一行,其中(loc1,S1)和(loc1,S2)之和, 和(loc2,S1)和(loc2,S2)的均值

  loc1    loc2  
  sum     mean    
  S1 S2   S1 S2  
  14 15    2  3  

如何使用“ agg”功能进行此计算? 有什么解决方法吗?

p.s。我知道我可以像回答Pivot table with multiple aggfunc sum and normalize one column那样来做, 但似乎有点“非pythonic”。

6 个答案:

答案 0 :(得分:2)

您可以对DataFrame.aggDataFrame.stack使用字典理解,对MultiIndex Series使用concat的最后Series.to_frame并转置一行DataFrame

d = {'loc1':'sum','loc2':'mean'}

df1 = pd.concat({k: df[k].agg([v]).stack() for k, v in d.items()}).to_frame().T
print (df1)
  loc1       loc2     
    sum       mean     
     S1    S2   S1   S2
0  15.0  14.0  2.6  2.0

答案 1 :(得分:1)

如果我对您的理解正确,那么您想对每个loc的每一行求和。我们需要在分组依据中指定levelaxis

df.groupby(level=0, axis=1).sum(axis=1)

loc      loc1      loc2
a   -0.159510  0.669699
b    0.406272  2.258626
c   -0.703832  0.274719
d   -1.453601 -0.480166
e    1.128587  0.504887

要分配回去,我们可以使用join,因为索引保持不变:

dfn = df.join(df.groupby(level=0, axis=1).sum(axis=1))

   (loc1, S1)  (loc1, S2)  (loc2, S1)  (loc2, S2)      loc1      loc2
a   -0.540104    0.380594    0.591548    0.078151 -0.159510  0.669699
b   -0.161479    0.567751    1.392222    0.866404  0.406272  2.258626
c   -0.549657   -0.154175    0.447627   -0.172908 -0.703832  0.274719
d   -1.811309    0.357709    0.124907   -0.605073 -1.453601 -0.480166
e    2.274189   -1.145603    0.458101    0.046786  1.128587  0.504887

请注意,您的MultiIndex列已变平。

要保持您的MultiIndex级别,我们必须创建一个称为sum的人工级别:

dfg = df.groupby(level=0, axis=1).sum(axis=1)
dfg.columns = pd.MultiIndex.from_product([dfg.columns, ['sum']])

dfn = df.join(dfg)

loc      loc1                loc2                loc1      loc2
S          S1        S2        S1        S2       sum       sum
a   -0.540104  0.380594  0.591548  0.078151 -0.159510  0.669699
b   -0.161479  0.567751  1.392222  0.866404  0.406272  2.258626
c   -0.549657 -0.154175  0.447627 -0.172908 -0.703832  0.274719
d   -1.811309  0.357709  0.124907 -0.605073 -1.453601 -0.480166
e    2.274189 -1.145603  0.458101  0.046786  1.128587  0.504887

最后,如果您希望按loc对列进行排序,请使用sort_index

dfn.sort_index(axis=1)

loc      loc1                          loc2                    
S          S1        S2       sum        S1        S2       sum
a   -0.540104  0.380594 -0.159510  0.591548  0.078151  0.669699
b   -0.161479  0.567751  0.406272  1.392222  0.866404  2.258626
c   -0.549657 -0.154175 -0.703832  0.447627 -0.172908  0.274719
d   -1.811309  0.357709 -1.453601  0.124907 -0.605073 -0.480166
e    2.274189 -1.145603  1.128587  0.458101  0.046786  0.504887

答案 2 :(得分:1)

是的,似乎不支持带有pd.MultiIndex并在agg中使用dictionary的数据帧,但是,这里的解决方法将生成所需的输出。

df_sum = df.agg('sum')[['loc1']].rename('sum').to_frame().stack().reorder_levels([0,2,1])
df_avg = df.agg('mean')[['loc2']].rename('mean').to_frame().stack().reorder_levels([0,2,1])
pd.concat([df_sum, df_avg]).to_frame().T

输出:

loc  loc1       loc2     
      sum       mean     
S      S1    S2   S1   S2
0    11.0  15.0  3.4  2.6

答案 3 :(得分:1)

没有直接的方法可以实现所需的输出。间接方法之一是使用dict理解来构建agg字典。之后,使用此字典访问agg,并在列和索引之间切换以获取所需的输出:

ops_dict = {'loc1':'sum', 'loc2':'mean'}
agg_dict = {(x,y): [ops_dict[x]] for x,y in df.columns}
df_agg = df.agg(agg_dict).stack([0,1]).swaplevel(0,1).sort_index(0).to_frame().T

Out[65]:
   loc1       loc2
    sum       mean
     S1    S2   S1   S2
0  14.0  15.0  2.0  3.0

或在每个pd.concat的直接keyssum上对参数mean使用locX

df_agg = pd.concat([df[['loc1']].sum(), df[['loc2']].mean()], 
                   keys=['sum','mean']).swaplevel(0,1).to_frame().T

df_agg = pd.concat([df['loc1'].sum(), df['loc2'].mean()], 
                   keys=[('loc1','sum'), ('loc2','mean')]).to_frame().T

Out[67]:
loc  loc1       loc2
      sum       mean
S      S1    S2   S1   S2
0    14.0  15.0  2.0  3.0

答案 4 :(得分:1)

我们可以做到

new_df = (df.stack('S')
            .groupby(level='S')
            .agg(loc1_sum = ('loc1', 'sum'), loc2_mean = ('loc2', 'mean')))
print(new_df)
    loc1_sum  loc2_mean
S                      
S1        11        2.0
S2        10        1.8

new_df.columns = pd.MultiIndex.from_tuples(map(tuple, new_df.columns.str.split('_')))
result = new_df.unstack().to_frame().T
print(result)

   loc1       loc2     
    sum       mean     
S    S1    S2   S1   S2
0  11.0  10.0  2.0  1.8

答案 5 :(得分:1)

不幸的是,对列(axis = 1)上agg的支持不如对行的完整。解决方案是通过两个agg调用来实现。

创建聚合

o1 = df['loc1'].agg('sum').rename('sum').to_frame()
o2 = df['loc2'].agg('mean').rename('mean').to_frame()

合并聚合

result = pd.concat([o1,o2],axis=1, keys=['loc1', 'loc2'])

最后进行一些调整,以将数据转换为所需的格式

result = result.unstack().to_frame().T

结果

  loc1       loc2     
   sum       mean     
S   S1    S2   S1   S2
0  9.0  10.0  2.4  2.4