Выбор строк из фрейма 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']
Нету. Это также не удается.
Так как же выбрать все строки, где:
- group1 == 'a'
- group1 == 'a' & group2 == 'c'
- group2 == 'c'
- group1 в ['a', 'b', 'c']
Ответы
Ответ 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.