Pandas 1.0.1 - как индексировать DataFrame с помощью MultiIndex, используя список, содержащий слайсер - PullRequest
2 голосов
/ 29 марта 2020

В качестве примера набора данных -

In [12]: import numpy as np; import pandas as pd                                                     

In [24]: data_raw = pd.DataFrame([  
    ...:      ...: {'frame': 1, 'face': np.NaN, 'lmark': np.NaN, 'x': np.NaN, 'y': np.NaN},  
    ...:      ...: {'frame': 197, 'face': 0, 'lmark': 1, 'x': 969, 'y': 737},  
    ...:      ...: {'frame': 197, 'face': 0, 'lmark': 2, 'x': 969, 'y': 740},  
    ...:      ...: {'frame': 197, 'face': 0, 'lmark': 3, 'x': 970, 'y': 744},  
    ...:      ...: {'frame': 197, 'face': 0, 'lmark': 4, 'x': 972, 'y': 748},  
    ...:      ...: {'frame': 197, 'face': 0, 'lmark': 5, 'x': 973, 'y': 752},  
    ...:      ...: {'frame': 300, 'face': 0, 'lmark': 1, 'x': 745, 'y': 367},   
    ...:      ...: {'frame': 300, 'face': 0, 'lmark': 2, 'x': 753, 'y': 411},   
    ...:      ...: {'frame': 300, 'face': 0, 'lmark': 3, 'x': 759, 'y': 455},  
    ...:      ...: {'frame': 301, 'face': 0, 'lmark': 1, 'x': 741, 'y': 364},    
    ...:      ...: {'frame': 301, 'face': 0, 'lmark': 2, 'x': 746, 'y': 408},    
    ...:      ...: {'frame': 301, 'face': 0, 'lmark': 3, 'x': 750, 'y': 452}]).set_index(['frame', 'face', 'lmark'])                                        

В Pandas 1.0.3, я мог бы отфильтровать строки выше в DataFrame, где lmark> 3 со следующими -

data_filtered = data_raw.loc[(slice(None), slice(None), [np.NaN, slice(3)]), :]

, но в Pandas 1.1.0, то же утверждение не выполняется с

TypeError: unhashable type: 'slice'

, очевидно, это изменение в design .

В этом случае как Могу ли я отфильтровать строки DataFrame ниже, где lmark> 3?

Ответы [ 2 ]

2 голосов
/ 29 марта 2020

Выбор с помощью IndexSlice и slice, работающий корректно только в некоторых версиях, поэтому я предлагаю использовать другой подход, выбирая по условию (ам):

Фильтрация по DataFrame.query :

vals = [np.nan,1,2,3]
df = data_raw.query('lmark in @vals')

Или Index.isin:

vals = [np.nan,1,2,3]
df = data_raw[data_raw.index.get_level_values('lmark').isin(vals)]

Если хотите, выберите все значения без >3:

df = data_raw[~(data_raw.index.get_level_values('lmark') > 3)]

Или все значения <3 с пропущенными значениями: </p>

i = data_raw.index.get_level_values('lmark')
df = data_raw[(i <= 3) | i.isna()]

или первые 3 строки на первый уровень по GroupBy.head:

df = data_raw.groupby(level=0).head(3)

print (df)
                      x      y
frame face lmark              
1     NaN  NaN      NaN    NaN
197   0.0  1.0    969.0  737.0
           2.0    969.0  740.0
           3.0    970.0  744.0
300   0.0  1.0    745.0  367.0
           2.0    753.0  411.0
           3.0    759.0  455.0
301   0.0  1.0    741.0  364.0
           2.0    746.0  408.0
           3.0    750.0  452.0
2 голосов
/ 29 марта 2020

Примечание. Не уверен в версиях до Pandas 1.0. Если вам приходится иметь дело с версиями, меньшими Pandas 1.0, решение @ jezrael будет гораздо более стабильным.

Не знаю, соответствует ли это вашему варианту использования, где вы хотите, чтобы на lmark были только строки меньше 3: Многоиндексная нарезка

#allows for easier slicing than Slice(None)
idx = pd.IndexSlice

#list the data u want to keep ... including np.nan
data_raw.loc[idx[:,:,[np.nan,1,2,3]],:]

                           x    y
frame   face    lmark                   
1        NaN    NaN      NaN    NaN
197     0.0     1.0     969.0   737.0
                2.0     969.0   740.0
                3.0     970.0   744.0
300     0.0     1.0     745.0   367.0
                2.0     753.0   411.0
                3.0     759.0   455.0
301     0.0     1.0     741.0   364.0
                2.0     746.0   408.0
                3.0     750.0   452.0
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...