¿Cuáles son las formas más comunes de pandas para seleccionar/filtrar filas de un marco de datos cuyo índice es un índice múltiple ?
Suposiciones para simplificar:
mux = pd.MultiIndex.from_arrays([ list('aaaabbbbbccddddd'), list('tuvwtuvwtuvwtuvw') ], names=['one', 'two']) df = pd.DataFrame({'col': np.arange(len(mux))}, mux) col one two at 0 u 1 v 2 w 3 bt 4 u 5 v 6 w 7 t 8 cu 9 v 10 dw 11 t 12 u 13 v 14 w 15
¿Cómo selecciono las filas que tienen "a" en el nivel "uno"?
col one two at 0 u 1 v 2 w 3Además, ¿cómo podría eliminar el nivel "uno" en la salida?
col two t 0 u 1 v 2 w 3 Pregunta 1b
¿Cómo divido todas las filas con el valor "t" en el nivel "dos"?
col one two at 0 bt 4 t 8 dt 12¿Cómo puedo seleccionar las filas correspondientes a los elementos "b" y "d" en el nivel "uno"?
col one two bt 4 u 5 v 6 w 7 t 8 dw 11 t 12 u 13 v 14 w 15 Pregunta 2b
¿Cómo obtendría todos los valores correspondientes a "t" y "w" en el nivel "dos"?
col one two at 0 w 3 bt 4 w 7 t 8 dw 11 t 12 w 15(x, y) ¿Cómo recupero una sección transversal, es decir, una sola fila que tiene valores específicos para el índice de df ? Específicamente, ¿cómo recupero la sección transversal de ('c', 'u') , dada por
col one two cu 9[(a, b), (c, d), ...] ¿Cómo selecciono las dos filas correspondientes a ('c', 'u') y ('a', 'w') ?
col one two cu 9 aw 3¿Cómo puedo recuperar todas las filas correspondientes a "a" en el nivel "uno" o "t" en el nivel "dos"?
col one two at 0 u 1 v 2 w 3 bt 4 t 8 dt 12¿Cómo puedo cortar secciones transversales específicas? Para "a" y "b", me gustaría seleccionar todas las filas con subniveles "u" y "v", y para "d", me gustaría seleccionar filas con subnivel "w".
col one two au 1 v 2 bu 5 v 6 dw 11 w 15La pregunta 7 utilizará una configuración única que consiste en un nivel numérico:
np.random.seed(0) mux2 = pd.MultiIndex.from_arrays([ list('aaaabbbbbccddddd'), np.random.choice(10, size=16) ], names=['one', 'two']) df2 = pd.DataFrame({'col': np.arange(len(mux2))}, mux2) col one two a 5 0 0 1 3 2 3 3 b 7 4 9 5 3 6 5 7 2 8 c 4 9 7 10 d 6 11 8 12 8 13 1 14 6 15
¿Cómo obtengo todas las filas donde los valores en el nivel "dos" son mayores que 5?
col one two b 7 4 9 5 c 7 10 d 6 11 8 12 8 13 6 15Nota: Esta publicación no explicará cómo crear MultiIndexes, cómo realizar operaciones de asignación en ellos o cualquier discusión relacionada con el rendimiento (estos son temas separados para otro momento).
Esto parece un gran caso para dfsql
df.sql(<SQL select statement>)https://github.com/mindsdb/dfsql
Un artículo completo al respecto aquí:
Recientemente me encontré con un caso de uso en el que tenía un marco de datos de índice múltiple de más de 3 niveles en el que no podía hacer que ninguna de las soluciones anteriores produjera los resultados que estaba buscando. Es muy posible que las soluciones anteriores, por supuesto, funcionen para mi caso de uso, y probé varias, sin embargo, no pude hacer que funcionaran con el tiempo que tenía disponible.
Estoy lejos de ser un experto, pero encontré una solución que no figuraba en las respuestas completas anteriores. No ofrezco ninguna garantía de que las soluciones sean óptimas.
Esta es una forma diferente de obtener un resultado ligeramente diferente a la Pregunta #6 anterior. (y probablemente otras preguntas también)
Específicamente estaba buscando:
Como una llave inglesa en los engranajes (sin embargo, totalmente reparable):
En el marco de datos del juguete a continuación:
index = pd.MultiIndex.from_product([['a','b'], ['stock1','stock2','stock3'], ['price','volume','velocity']]) df = pd.DataFrame([1,2,3,4,5,6,7,8,9, 10,11,12,13,14,15,16,17,18], index) 0 a stock1 price 1 volume 2 velocity 3 stock2 price 4 volume 5 velocity 6 stock3 price 7 volume 8 velocity 9 b stock1 price 10 volume 11 velocity 12 stock2 price 13 volume 14 velocity 15 stock3 price 16 volume 17 velocity 18Usando los siguientes trabajos, por supuesto:
df.xs(('stock1', 'velocity'), level=(1,2)) 0 a 3 b 12Pero quería un resultado diferente, así que mi método para obtener ese resultado fue:
df.iloc[df.index.isin(['stock1'], level=1) & df.index.isin(['velocity'], level=2)] 0 a stock1 velocity 3 b stock1 velocity 12Y si quisiera más de dos valores de un nivel y un solo valor (o más de 2) de otro nivel:
df.iloc[df.index.isin(['stock1','stock3'], level=1) & df.index.isin(['velocity'], level=2)] 0 a stock1 velocity 3 stock3 velocity 9 b stock1 velocity 12 stock3 velocity 18El método anterior es probablemente un poco torpe, sin embargo, descubrí que satisfacía mis necesidades y, como beneficio adicional, era más fácil de entender y leer para mí.