trying index iloc from drop columns python pandas

python - iloc - pandas: cortar un MultiIndex por rango de índice secundario



pandas select columns (4)

Tengo una serie con un MultiIndex como este:

import numpy as np import pandas as pd buckets = np.repeat([''a'',''b'',''c''], [3,5,1]) sequence = [0,1,5,0,1,2,4,50,0] s = pd.Series( np.random.randn(len(sequence)), index=pd.MultiIndex.from_tuples(zip(buckets, sequence)) ) # In [6]: s # Out[6]: # a 0 -1.106047 # 1 1.665214 # 5 0.279190 # b 0 0.326364 # 1 0.900439 # 2 -0.653940 # 4 0.082270 # 50 -0.255482 # c 0 -0.091730

Me gustaría obtener los valores s [''b''] donde el segundo índice ('' sequence '') está entre 2 y 10.

Cortar en el primer índice funciona bien:

s[''a'':''b''] # Out[109]: # bucket value # a 0 1.828176 # 1 0.160496 # 5 0.401985 # b 0 -1.514268 # 1 -0.973915 # 2 1.285553 # 4 -0.194625 # 5 -0.144112

Pero no en el segundo, al menos por lo que parecen ser las dos formas más obvias:

1) Esto devuelve los elementos 1 a 4, sin nada que ver con los valores del índice

s[''b''][1:10] # In [61]: s[''b''][1:10] # Out[61]: # 1 0.900439 # 2 -0.653940 # 4 0.082270 # 50 -0.255482

Sin embargo, si invierto el índice y el primer índice es entero y el segundo índice es una cadena, funciona:

In [26]: s Out[26]: 0 a -0.126299 1 a 1.810928 5 a 0.571873 0 b -0.116108 1 b -0.712184 2 b -1.771264 4 b 0.148961 50 b 0.089683 0 c -0.582578 In [25]: s[0][''a'':''b''] Out[25]: a -0.126299 b -0.116108


A partir de pandas 0.14.0, es posible dividir objetos de .loc proporcionando .loc una tupla que contiene objetos de .loc :

In [2]: s.loc[(''b'', slice(2, 10))] Out[2]: b 2 -1.206052 4 -0.735682 dtype: float64


Como responde Robbie-Clarken , desde 0.14 puede pasar una porción de la tupla que pasa a loc :

In [11]: s.loc[(''b'', slice(2, 10))] Out[11]: b 2 -0.65394 4 0.08227 dtype: float64

De hecho, puedes pasar una porción para cada nivel:

In [12]: s.loc[(slice(''a'', ''b''), slice(2, 10))] Out[12]: a 5 0.27919 b 2 -0.65394 4 0.08227 dtype: float64

Nota: la rebanada es inclusiva.

Respuesta antigua:

También puedes hacer esto usando:

s.ix[1:10, "b"]

(Es una buena práctica hacer en un solo ix / loc / iloc ya que esta versión permite la asignación).

Esta respuesta se escribió antes de la introducción de iloc a principios de 2013, es decir, la ubicación de posición / entero, que puede preferirse en este caso. La razón por la que se creó fue para eliminar la ambigüedad de los objetos pandas indexados a enteros, y ser más descriptivo: "Estoy cortando en posición".

s["b"].iloc[1:10]

Dicho esto, estoy un poco en desacuerdo con los documentos que ix es:

La forma más robusta y consistente.

no lo es, la forma más consistente es describir lo que estás haciendo:

  • usar loc para etiquetas
  • usar iloc para posicionar
  • Usa ix para ambos (si realmente tienes que hacerlo)

Recuerda el zen de python :

explícito es mejor que implícito


La mejor manera en que puedo pensar es usar "seleccionar" en este caso. Aunque incluso dice en la documentación que "este método debe usarse solo cuando no hay una forma más directa".

Indexación y selección de datos.

In [116]: s Out[116]: a 0 1.724372 1 0.305923 5 1.780811 b 0 -0.556650 1 0.207783 4 -0.177901 50 0.289365 0 1.168115 In [117]: s.select(lambda x: x[0] == ''b'' and 2 <= x[1] <= 10) Out[117]: b 4 -0.177901


No estoy seguro si esto es ideal pero funciona creando una máscara.

In [59]: s.index Out[59]: MultiIndex [(''a'', 0) (''a'', 1) (''a'', 5) (''b'', 0) (''b'', 1) (''b'', 2) (''b'', 4) (''b'', 50) (''c'', 0)] In [77]: s[(tpl for tpl in s.index if 2<=tpl[1]<=10 and tpl[0]==''b'')] Out[77]: b 2 -0.586568 4 1.559988

EDITAR: la solución de Hayden es el camino a seguir