Умножение двух мультииндексных фреймов данных с разными, но похожими индексами и столбцами - PullRequest
3 голосов
/ 03 февраля 2020

Пожалуйста, рассмотрите эти два кадра данных.

import pandas as pd
cols = ['F', 'D']

s_ind = pd.MultiIndex.from_arrays([['A', 'A', 'A'], ['B', 'B', 'B'], ['C', 'C', 'C'], ['D', 'E', 'F']],
                                  names=('cat1', 'cat2', 'cat3', 'cat4'))
s = pd.DataFrame(data=[[1,4], [2,5], [3,6]], columns=cols, index=s_ind)

Итак, s:


                      F  D
cat1 cat2 cat3 cat4      
A    B    C    D     1  4
               E     2  5
               F     3  6

и ...

ib_ind = pd.MultiIndex.from_arrays([['A'], ['B'], ['C']], names=['cat1', 'cat2', 'cat3'])
ib = pd.DataFrame(data=[[7, 8]], columns=cols, index=ib_ind)

Итак, ib:

                 F  D
cat1 cat2 cat3      
A    B    C     7  8

Если я умножу, используя ось 0 (показана) или 1 (не показана), я получу одинаковые результаты. См. Здесь:

print(ib.mul(s, axis=0))
                      F   D
cat1 cat2 cat3 cat4        
A    B    C    D      7  32
               E     14  40
               F     21  48

Вопрос: Как выполнить умножение таким образом, чтобы я получал его в качестве выходного сигнала?

print(pd.DataFrame(data=[[8*1,8*4], [0,0], [7*3,7*6]], columns=cols, index=s_ind))
                      F   D
cat1 cat2 cat3 cat4        
A    B    C    D      8  32
               E      0   0
               F     21  42

Обратите внимание, что строка E равна 0, потому что нет соответствующего E столбец в ib, чтобы умножить. В качестве альтернативы, nans тоже подойдет.

1 Ответ

4 голосов
/ 03 февраля 2020

вы можете попробовать unstack для s и multiply ib с level=1 на axis=1, затем stack обратно и reindex с fill_value=0

final = ib.mul(s.unstack(),level=1,axis=1).stack().reindex(s.index,fill_value=0)
# or: ib.mul(s.unstack('cat4'),level=1,axis=1).stack().reindex(s.index,fill_value=0)

Другой способ, предложенный @piRSquared, который предусматривает изменение формы всего один раз (а значит, быстрее), составляет rename индекс к индексу, которому вы хотите соответствовать при умножении, затем stack и reindex после умножения:

s.mul(ib.rename_axis('cat4', axis=1).stack().reindex(s.index, fill_value=0), axis=0) 

                        F     D
cat1 cat2 cat3 cat4            
A    B    C    D      8.0  32.0
               E      0.0   0.0
               F     21.0  42.0
...