Selección de filas de un dataframe de Pandas con un índice compuesto (jerárquico)

Sospecho que esto es trivial, pero aún tengo que descubrir el conjuro que me permitirá seleccionar filas de un dataframe de Pandas basado en los valores de una clave jerárquica. Entonces, por ejemplo, imagine que tenemos el siguiente dataframe:

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 luce como podríamos esperar:

introduzca la descripción de la imagen aquí

Si df no estuviera indexado en el grupo 1, podría hacer lo siguiente:

 df['group1' == 'a'] 

Pero eso falla en este dataframe con un índice. Así que tal vez debería pensar en esto como una serie de Pandas con un índice jerárquico:

 df['a','c'] 

No Eso también falla.

Entonces, ¿cómo selecciono todas las filas donde:

  1. grupo1 == ‘a’
  2. group1 == ‘a’ & group2 == ‘c’
  3. grupo2 == ‘c’
  4. grupo1 en [‘a’, ‘b’, ‘c’]

Intenta usar xs para ser muy preciso:

 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 

Sintaxis como la siguiente funcionará:

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

Desde group1 y group2 son índices. ¡Por favor perdona mi bash anterior!

Para obtener solo el segundo índice, creo que tienes que intercambiar índices:

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

Pero estoy seguro de que Wes me corregirá si me equivoco.

En Python 0.19.0 hay un nuevo enfoque sugerido, que se explica aquí 1 . Creo que el ejemplo más claro que dan es el siguiente, en el que se dividen de una indexación de cuatro niveles. Así es como se hace el 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 ab 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 

Y así es como seleccionan las diferentes filas:

 In [51]: dfmi.loc[(slice('A1','A3'),slice(None), ['C1','C3']),:] Out[51]: lvl0 ab 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 

Así que, simplemente, en df.loc[(indices),:] , especifique los índices que desea seleccionar por nivel, desde el nivel más alto hasta el más bajo. Si no desea realizar una selección de los niveles más bajos de índices, puede omitir su especificación. Si no desea crear una división entre otros niveles especificados, agregue la slice(None) . Ambos casos se muestran en el ejemplo, donde se omite el nivel D y se especifica el nivel B entre A y C.