У меня есть столбец 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

Для DataFrame без MultiIndex я бы сделал:

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

Но это не работает с MultiIndex. Желаемый результат

    foo
    bar    baz
1     4      6
2    12     14

Как я могу этого добиться?

0
Christian Brinch 22 Сен 2021 в 17:29

2 ответа

Лучший ответ

Серии могут быть переданы в 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
1
Henry Ecker 22 Сен 2021 в 14:52

Вы можете подгруппировать уровень и восстановить его после 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

NB. технически код, который вы использовали, должен работать с 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)
1
mozway 22 Сен 2021 в 14:35