Подтвердить что ты не робот

Выбор строк из фрейма Pandas с составным (иерархическим) индексом

Я подозреваю, что это тривиально, но я еще не обнаружил заклинание, которое позволит мне выбирать строки в кадре данных Pandas на основе значений иерархического ключа. Например, представьте, что у нас есть следующий фрейм данных:

import pandas
df = pandas.DataFrame({'group1': ['a','a','a','b','b','b'],
                       'group2': ['c','c','d','d','d','e'],
                       'value1': [1.1,2,3,4,5,6],
                       'value2': [7.1,8,9,10,11,12]
})
df = df.set_index(['group1', 'group2'])

df выглядит так, как мы ожидаем:

enter image description here

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

df['group1' == 'a']

Но это терпит неудачу на этом фрейме данных с индексом. Так что, возможно, мне следует подумать об этом как о серии Панд с иерархическим индексом:

df['a','c']

Нету. Это также не удается.

Так как же выбрать все строки, где:

  1. group1 == 'a'
  2. group1 == 'a' & group2 == 'c'
  3. group2 == 'c'
  4. group1 в ['a', 'b', 'c']
4b9b3361

Ответ 1

Попробуйте использовать xs, чтобы быть очень точным:

In [5]: df.xs('a', level=0)
Out[5]: 
        value1  value2
group2                
c          1.1     7.1
c          2.0     8.0
d          3.0     9.0

In [6]: df.xs('c', level='group2')
Out[6]: 
        value1  value2
group1                
a          1.1     7.1
a          2.0     8.0

Ответ 2

Синтаксис, подобный приведенному ниже, будет работать:

df.ix['a']
df.ix['a'].ix['c']

так как group1 и group2 - индексы. Пожалуйста, простите мою предыдущую попытку!

Чтобы получить только второй индекс, я думаю, вам нужно поменять индексы:

df.swaplevel(0,1).ix['c']

Но я уверен, что Уэс исправит меня, если я ошибаюсь.

Ответ 3

В Python 0.19.0 есть новый предложенный подход, который объясняется здесь 1. Я считаю, что самым ярким примером, который они дают, является следующее, в котором они срезают от четырехуровневой индексации. Именно так создается dataframe:

In [46]: def mklbl(prefix,n):
   ....:     return ["%s%s" % (prefix,i)  for i in range(n)]
   ....: 

In [47]: miindex = pd.MultiIndex.from_product([mklbl('A',4),
   ....:                                       mklbl('B',2),
   ....:                                       mklbl('C',4),
   ....:                                       mklbl('D',2)])
   ....: 

In [48]: micolumns = pd.MultiIndex.from_tuples([('a','foo'),('a','bar'),
   ....:                                        ('b','foo'),('b','bah')],
   ....:                                       names=['lvl0', 'lvl1'])
   ....: 

In [49]: dfmi = pd.DataFrame(np.arange(len(miindex)*len(micolumns)).reshape((len(miindex),len(micolumns))),
   ....:                     index=miindex,
   ....:                     columns=micolumns).sort_index().sort_index(axis=1)
   ....: 

In [50]: dfmi
Out[50]: 
lvl0           a         b     
lvl1         bar  foo  bah  foo
A0 B0 C0 D0    1    0    3    2
         D1    5    4    7    6
      C1 D0    9    8   11   10
         D1   13   12   15   14
      C2 D0   17   16   19   18
         D1   21   20   23   22
      C3 D0   25   24   27   26
...          ...  ...  ...  ...
A3 B1 C0 D1  229  228  231  230
      C1 D0  233  232  235  234
         D1  237  236  239  238
      C2 D0  241  240  243  242
         D1  245  244  247  246
      C3 D0  249  248  251  250
         D1  253  252  255  254

И так они выбирают разные строки:

In [51]: dfmi.loc[(slice('A1','A3'),slice(None), ['C1','C3']),:]
Out[51]: 
lvl0           a         b     
lvl1         bar  foo  bah  foo
A1 B0 C1 D0   73   72   75   74
         D1   77   76   79   78
      C3 D0   89   88   91   90
         D1   93   92   95   94
   B1 C1 D0  105  104  107  106
         D1  109  108  111  110
      C3 D0  121  120  123  122
...          ...  ...  ...  ...
A3 B0 C1 D1  205  204  207  206
      C3 D0  217  216  219  218
         D1  221  220  223  222
   B1 C1 D0  233  232  235  234
         D1  237  236  239  238
      C3 D0  249  248  251  250
         D1  253  252  255  254

Так просто, в df.loc[(indices),:] вы указываете индексы, которые вы хотите выбрать для каждого уровня, от самого высокого уровня до самого низкого. Если вы не хотите выбирать наименьший уровень индексов, вы можете опустить их. Если вы не хотите делать срез между другими указанными уровнями, добавьте slice(None). Оба примера показаны в примере, где уровень D опущен, а уровень B задается между A и C.