Je soupçonne que cela est trivial, mais je n'ai pas encore découvert l'incantation qui me permettra de sélectionner des lignes dans une trame de données Pandas basée sur les valeurs d'une clé hiérarchique. Donc, par exemple, imaginez nous avons le dataframe suivant:
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 ressemble comme on peut s'y attendre:
Si df n'était pas indexé sur le groupe 1, je pourrais faire ce qui suit:
df['group1' == 'a']
Mais cela échoue sur cette trame de données avec un index. Alors peut-être que je devrais penser à cela comme une série Pandas avec un index hiérarchique:
df['a','c']
Nan. Cela échoue également.
Alors, comment puis-je sélectionner toutes les lignes où:
Essayez d'utiliser xs
pour être très précis:
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
Une syntaxe comme celle-ci fonctionnera:
df.ix['a']
df.ix['a'].ix['c']
puisque group1
et group2
sont des indices. Veuillez pardonner ma tentative précédente!
Pour arriver au deuxième indice seulement, je pense que vous devez échanger les indices:
df.swaplevel(0,1).ix['c']
Mais je suis sûr que Wes me corrigera si je me trompe.
Dans Python 0.19.0 il y a une nouvelle approche suggérée, qui est expliquée ici 1 . Je crois que l'exemple le plus clair qu'ils donnent est le suivant, dans lequel ils partent de une indexation à quatre niveaux. Voici comment la trame de données est réalisée:
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
Et voici comment ils sélectionnent les différentes lignes:
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
Donc tout simplement, dans df.loc[(indices),:]
, vous spécifiez les indices que vous souhaitez sélectionner par niveau, du plus haut au plus bas. Si vous ne souhaitez pas sélectionner les niveaux d'indice les plus bas, vous pouvez omettre de les spécifier. Si vous ne voulez pas faire de tranche entre les autres niveaux spécifiés, vous ajoutez slice(None)
. Les deux cas sont illustrés dans l'exemple, où le niveau D est omis et le niveau B est spécifié entre A et C.