pandas мультииндексное выделение с условием на столбцы - PullRequest
4 голосов
/ 09 января 2020

У меня проблемы с фильтрацией на многоиндексном фрейме данных.

import numpy as np
import pandas as pd
df = pd.DataFrame(np.random.randn(6, 6), 
  columns=pd.MultiIndex.from_arrays((['Team_1','Team_1','Team_1','Team_1','Team_1','Team_1'],
  ['A','A','A','B','B','B'], ['a', 'b', 'c', 'a', 'b', 'c'])))

, который выглядит следующим образом:

     Team_1                                                  
          A                             B                    
          a         b         c         a         b         c
0  1.663478  1.121481 -0.675905 -1.286932 -0.713381  0.835101
1  0.076587  1.334063 -1.804435 -0.892450 -0.349493 -1.448643
2  0.485618  0.675481 -0.488584 -0.354583  1.827532 -1.184389
3 -0.531397 -0.145830 -1.143331 -0.871459 -0.009081 -1.741627
4  0.355948 -2.275475  0.543201 -0.099087 -1.114334 -1.248298
5  1.448409 -0.974127  2.004364 -0.880845  1.195134  0.392949

Я хотел бы вывести df, где a и b предъявляют некоторые требования: если оба они верны, включите также столбец c. Например, вывод данных с разрезами a>0 и b<0 должен выглядеть так:

     Team_1                                                  
          A                             B                    
          a         b         c         a         b         c
0  1.663478       NaN       NaN       NaN -0.713381       NaN
1  0.076587       NaN       NaN       NaN -0.349493       NaN
2  0.485618       NaN       NaN -0.354583       NaN       NaN
3       NaN -0.145830       NaN       NaN -0.009081       NaN
4  0.355948 -2.275475  0.543201       NaN -1.114334       NaN
5  1.448409 -0.974127  2.004364       NaN       NaN       NaN

Для начала я могу сделать базовый c selection (df.iloc[:, df.columns.get_level_values(2) == 'a'] > 0), но не уверен, откуда go есть.

Ответы [ 2 ]

2 голосов
/ 09 января 2020

Другой вариант - использовать stack / unstack.

result = (
    df.stack(level=[0, 1])
      .assign(
          c=lambda df: np.where(
              (df["a"] > 0) & (df["b"] < 0),
              df["c"], np.nan
          )
          a=lambda df: np.where(
              df["a"] > 0, df["a"], np.nan
          ),
          b=lambda df: np.where(
              df["b"] < 0, df["b"], np.nan
          )
      ).unstack(level=[1, 2])
      .reorder_levels([1, 2, 0], axis=1)
      .sort_index(level=1, axis=1)
)

Если мы начнем с df, который выглядит следующим образом:

     Team_1                                                  
          A                             B                    
          a         b         c         a         b         c
0  0.622728 -1.059337  0.154738 -1.118633  0.336635  1.173941
1  0.166443  0.236547  0.690746  0.169085 -0.107237 -0.539768
2 -1.270542  0.525559  0.335747  0.455872 -0.523938  0.508105
3  1.964184  0.281073  0.567805  0.012256  2.773986 -0.900674
4  1.997804 -0.621523 -0.253128  1.867092  0.134846  2.729482
5  0.860470 -0.293951 -1.581081 -2.014744  1.357025 -1.007692

Выход result будет:

     Team_1                                                  
          A                             B                    
          a         b         c         a         b         c
0  0.622728 -1.059337  0.154738       NaN       NaN       NaN
1  0.166443       NaN       NaN  0.169085 -0.107237 -0.539768
2       NaN       NaN       NaN  0.455872 -0.523938  0.508105
3  1.964184       NaN       NaN  0.012256       NaN       NaN
4  1.997804 -0.621523 -0.253128  1.867092       NaN       NaN
5  0.860470 -0.293951 -1.581081       NaN       NaN       NaN
2 голосов
/ 09 января 2020

Используйте xs, чтобы выбрать столбцы и удалить этот уровень MultiIndex. 'c' - это проверка & между первыми двумя масками. concat с keys, чтобы добавить метки обратно, а затем подставить исходный DataFrame с этой полной логической маской.

m1 = df.xs('a', level=2, axis=1).gt(0)  # a > 0
m2 = df.xs('b', level=2, axis=1).lt(0)  # b < 0
m = pd.concat([m1, m2, m1&m2], axis=1, keys=['a', 'b', 'c']).reorder_levels([1,2,0], axis=1)

df[m]   # used np.random.seed(13) in creation.
     Team_1                                            
          A                             B              
          a         b         c         a         b   c
0       NaN       NaN       NaN  0.451812       NaN NaN
1  1.350188       NaN       NaN       NaN -0.788989 NaN
2  0.562847 -0.243326  0.913741  0.317351       NaN NaN
3  0.606289 -0.026772 -0.984161  1.190705       NaN NaN
4       NaN       NaN       NaN       NaN       NaN NaN
5  0.490872       NaN       NaN       NaN       NaN NaN
...