Pandas Multiindex и Groupby - PullRequest
       29

Pandas Multiindex и Groupby

0 голосов
/ 18 мая 2018

У меня есть пандас DataFrame с 3-уровневыми многоиндексными столбцами.Нижний уровень - это всегда два столбца, и я хочу вычислить разницу этих двух столбцов в каждой из групп, определенных первыми двумя уровнями.

import numpy as np
import pandas as pd

multi_idx = pd.MultiIndex.from_product([['A', 'B', 'C'], ['a', 'b'], ['L', 'S']],
                                       names=['level_1', 'level_2', 'level_3'])
test_df = pd.DataFrame(np.random.randn(10, len(multi_idx)), columns=multi_idx)

Итак, другими словами, я хочу вычислить'L' - 'S' в каждой группе.

Вот моя попытка использования группы панд:

net = test_df.groupby(level=['level_1', 'level_2'], axis=1, group_keys=False)\
             .apply(lambda x: x.xs('L', axis=1, level='level_3', drop_level=True) -
                              x.xs('S', axis=1, level='level_3', drop_level=True))

, но она возвращает все NaN:

net
level_1   A               B               C            
level_2   a       b       a       b       a       b    
level_3   L   S   L   S   L   S   L   S   L   S   L   S
0       NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
1       NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
2       NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
3       NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
4       NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
5       NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
6       NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
7       NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
8       NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
9       NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN

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

Я использую pandas 0.21 с Python 3.4

1 Ответ

0 голосов
/ 18 мая 2018

Для меня это работает в версии pandas 0.23.0, но я думаю, что лучше выбрать xs и вычесть:

np.random.seed(10)
multi_idx = pd.MultiIndex.from_product([['A', 'B', 'C'], ['a', 'b'], ['L', 'S']],
                                       names=['level_1', 'level_2', 'level_3'])
test_df = pd.DataFrame(np.random.randint(10, size=(10, len(multi_idx))), columns=multi_idx)
print (test_df)
level_1  A           B           C         
level_2  a     b     a     b     a     b   
level_3  L  S  L  S  L  S  L  S  L  S  L  S
0        9  4  0  1  9  0  1  8  9  0  8  6
1        4  3  0  4  6  8  1  8  4  1  3  6
2        5  3  9  6  9  1  9  4  2  6  7  8
3        8  9  2  0  6  7  8  1  7  1  4  0
4        8  5  4  7  8  8  2  6  2  8  8  6
5        6  5  6  0  0  6  9  1  8  9  1  2
6        8  9  9  5  0  2  7  3  0  4  2  0
7        3  3  1  2  5  9  0  1  0  1  9  0
8        9  2  1  1  0  0  5  9  0  4  6  6
9        0  2  3  3  2  6  0  5  1  3  6  5

df = test_df.xs('L', axis=1, level='level_3') - test_df.xs('S', axis=1, level='level_3')
print (df)
level_1  A     B     C   
level_2  a  b  a  b  a  b
0        5 -1  9 -7  9  2
1        1 -4 -2 -7  3 -3
2        2  3  8  5 -4 -1
3       -1  2 -1  7  6  4
4        3 -3  0 -4 -6  2
5        1  6 -6  8 -1 -1
6       -1  4 -2  4 -4  2
7        0 -1 -4 -1 -1  9
8        7  0  0 -4 -4  0
9       -2  0 -4 -5 -2  1

net = test_df.groupby(level=['level_1', 'level_2'], axis=1, group_keys=False)\
             .apply(lambda x: x.xs('L', axis=1, level='level_3', drop_level=True) -
                              x.xs('S', axis=1, level='level_3', drop_level=True))
print (net)
level_1  A           B           C         
level_2  a     b     a     b     a     b   
level_3  L  S  L  S  L  S  L  S  L  S  L  S
0        5  5 -1 -1  9  9 -7 -7  9  9  2  2
1        1  1 -4 -4 -2 -2 -7 -7  3  3 -3 -3
2        2  2  3  3  8  8  5  5 -4 -4 -1 -1
3       -1 -1  2  2 -1 -1  7  7  6  6  4  4
4        3  3 -3 -3  0  0 -4 -4 -6 -6  2  2
5        1  1  6  6 -6 -6  8  8 -1 -1 -1 -1
6       -1 -1  4  4 -2 -2  4  4 -4 -4  2  2
7        0  0 -1 -1 -4 -4 -1 -1 -1 -1  9  9
8        7  7  0  0  0  0 -4 -4 -4 -4  0  0
9       -2 -2  0  0 -4 -4 -5 -5 -2 -2  1  1

Если нужноНовый столбец с вычитаемыми значениями. Одним из возможных решений является drop_level=False для не удаляемых уровней S и L, rename для того же имени новой метки и concat вместе:

a = test_df.xs('L', axis=1, level='level_3', drop_level=False).rename(columns={'L':'L-S'}, level=2)
b = test_df.xs('S', axis=1, level='level_3', drop_level=False).rename(columns={'S':'L-S'}, level=2)    

df = pd.concat([test_df, a - b], axis=1).sort_index(axis=1)
print (df)
level_1  A                   B                   C                 
level_2  a         b         a         b         a         b       
level_3  L L-S  S  L L-S  S  L L-S  S  L L-S  S  L L-S  S  L L-S  S
0        9   5  4  0  -1  1  9   9  0  1  -7  8  9   9  0  8   2  6
1        4   1  3  0  -4  4  6  -2  8  1  -7  8  4   3  1  3  -3  6
2        5   2  3  9   3  6  9   8  1  9   5  4  2  -4  6  7  -1  8
3        8  -1  9  2   2  0  6  -1  7  8   7  1  7   6  1  4   4  0
4        8   3  5  4  -3  7  8   0  8  2  -4  6  2  -6  8  8   2  6
5        6   1  5  6   6  0  0  -6  6  9   8  1  8  -1  9  1  -1  2
6        8  -1  9  9   4  5  0  -2  2  7   4  3  0  -4  4  2   2  0
7        3   0  3  1  -1  2  5  -4  9  0  -1  1  0  -1  1  9   9  0
8        9   7  2  1   0  1  0   0  0  5  -4  9  0  -4  4  6   0  6
9        0  -2  2  3   0  3  2  -4  6  0  -5  5  1  -2  3  6   1  5
...