DataFrame.index.levels показывает «лишние» значения после сокращения фрейма данных

#python #pandas #multi-index

#python #панды #мультииндексный

Вопрос:

Допустим, у меня есть большой large фрейм данных, который имеет мультииндекс в строках. Я сокращаю этот фрейм данных, выбирая только некоторые строки и присваивая результат small . В частности, small имеет меньше различных значений на 0-м уровне своего мультииндекса в строках, чем large .

Затем я хочу получить список различных значений на 0-м уровне MultiIndex в строках small , которые я вызываю small.index.levels[0] . Результат странный: он возвращает то же самое, large.index.levels[0] что и несмотря на то, что значений должно быть меньше.

Что происходит?

MWE:

 import pandas as pd
import numpy as np

np.random.seed(0)

idx = pd.MultiIndex.from_product([['John', 'Josh', 'Alex'], list('abcde')], 
                                 names=['Person', 'Letter'])
large = pd.DataFrame(data=np.random.randn(15, 2), 
                     index=idx, 
                     columns=['one', 'two'])
small = large.loc[['Jo'==d[0:2] for d in large.index.get_level_values('Person')]]

print small.index.levels[0]
print large.index.levels[0]
  

Вывод:

 Index([u'Alex', u'John', u'Josh'], dtype='object')
Index([u'Alex', u'John', u'Josh'], dtype='object')
  

Ожидаемый результат:

 Index([u'John', u'Josh'], dtype='object')
Index([u'Alex', u'John', u'Josh'], dtype='object')
  

Ответ №1:

Более эффективно это сделать.

 In [43]: large[large.index.get_level_values('Person').to_series().str.startswith('Jo').values]
Out[43]: 
                    one       two
Person Letter                    
John   a       1.764052  0.400157
       b       0.978738  2.240893
       c       1.867558 -0.977278
       d       0.950088 -0.151357
       e      -0.103219  0.410599
Josh   a       0.144044  1.454274
       b       0.761038  0.121675
       c       0.443863  0.333674
       d       1.494079 -0.205158
       e       0.313068 -0.854096
  

Чтобы ответить на ваш вопрос. Это деталь реализации. Использовать .get_level_values() (вместо доступа к внутреннему .levels

Вы можете сделать это, если хотите.

 In [13]: small.index.get_level_values('Person').unique()
Out[13]: array(['John', 'Josh'], dtype=object)

In [14]: large.index.get_level_values('Person').unique()
Out[14]: array(['John', 'Josh', 'Alex'], dtype=object)
  

Комментарии:

1. Я не совсем уверен, что вы ответили на мой вопрос. Моя цель — не выполнять фильтрацию от large до small . В моем small приведенном выше есть только те данные, которые мне нужны. Я хочу получить список различных значений на 0-м уровне мультииндекса small . (Например, large на Person уровне его MultiIndex могут быть сотни имен, и поэтому я могу не знать, что я получу, когда отфильтрую только имена, начинающиеся с 'Jo' . Но как только фильтрация будет завершена, я хочу посмотреть, что у меня получилось. Как вы предлагаете мне это сделать?