如何将 Pandas DataFrame 与 MultiIndex 列分组?

How to group Pandas DataFrame with MultiIndex columns?

我有一个 MultiIndex 列 Pandas DataFrame A:

       foo    
       bar   baz
s1_a     1     2
s1_b     3     4
s2_a     5     6
s2_b     7     8

我想根据来自另一个 DataFrame B 的键对数据进行分组:

       key
s1_a     1
s1_b     1
s2_a     2
s2_b     2

对于没有 MultiIndex 的 DataFrame,我会这样做:

pd.merge(A, B, left_index=True, right_index=True).groupby('key').sum()

但这不适用于 MultiIndex。期望的结果是

    foo
    bar    baz
1     4      6
2    12     14

我怎样才能做到这一点?

您可以在 merge 之后使用 pandas.concat:

对级别进行子集化和恢复
C = pd.concat({'foo': (pd.merge(A['foo'], B, left_index=True, right_index=True)
                         .groupby('key')
                         .sum()
                       )
              }, axis=1)

输出:

>>> C
    foo    
    bar baz
key        
1     4   6
2    12  14

注意。从技术上讲,您使用的代码应该使用 FutureWarning,但是您丢失了 MultiIndex 而不是获取元组

>>> pd.merge(A, B, left_index=True, right_index=True).groupby('key').sum()
     (foo, bar)  (foo, baz)
key                        
1             4           6
2            12          14

FutureWarning: merging between different levels is deprecated and will be removed in a future version. (2 levels on the left,1 on the right)

系列可以直接传递给groupby,石斑鱼会做适当的索引对齐,所以可以这样做:

A.groupby(B['key']).sum()
    foo    
    bar baz
key        
1     4   6
2    12  14

设置:

import numpy as np
import pandas as pd

idx = ['s1_a', 's1_b', 's2_a', 's2_b']
A = pd.DataFrame(
    np.arange(1, 9).reshape((-1, 2)),
    index=idx,
    columns=pd.MultiIndex.from_product([['foo'], ['bar', 'baz']])
)

B = pd.DataFrame({'key': [1, 1, 2, 2]}, index=idx)

请注意,这在很多情况下都有效,但不如合并持久:

B 变体 1:

B = pd.DataFrame({'key': [1, 2, 2]}, index=['s1_a', 's1_b', 's2_b'])
      key
s1_a    1  # No s2_a
s1_b    2
s2_b    2


A.groupby(B['key']).sum()

    foo    
    bar baz
key        
1.0   1   2
2.0  10  12

B 变体 2:

B = pd.DataFrame({'key': [1, 1, 2, 2]}, index=['s1_a', 's2_a', 's1_b', 's2_b'])
      key
s1_a    1
s2_a    1  # s1_a/s2_a together
s1_b    2
s2_b    2  # s1_b/s2_b together

A.groupby(B['key']).sum()

    foo    
    bar baz
key        
1     6   8
2    10  12