2012-01-18 40 views
29

que tienen una trama de datos en df pandas que fue construido usando pandas.read_table desde un archivo csv. El marco de datos tiene varias columnas y está indexado por una de las columnas (que es única, porque cada fila tiene un valor único para esa columna utilizada para la indexación).la selección a través de múltiples columnas con pandas pitón?

¿Cómo puedo seleccionar filas de mi marco de datos en base a filtro "complejo" aplicado a múltiples columnas? Puedo seleccionar fácilmente la porción de la trama de datos donde la columna colA es mayor que 10, por ejemplo:

df_greater_than10 = df[df["colA"] > 10] 

Pero lo que si quería un filtro como: seleccione el sector de df donde cualquier de las columnas son mayores de 10?

O donde el valor de colA es mayor que 10, pero el valor de colB es menor que 5?

¿Cómo son estas implementado en los pandas? Gracias.

Respuesta

36

Te animo a que plantees estas preguntas en el mailing list, pero en cualquier caso, sigue siendo un asunto de muy bajo nivel que trabaja con los arreglos subyacentes de NumPy. Por ejemplo, para seleccionar filas en las que el valor de cualquier columna supere, por ejemplo, 1,5 en este ejemplo:

In [11]: df 
Out[11]: 
      A  B  C  D  
2000-01-03 -0.59885 -0.18141 -0.68828 -0.77572 
2000-01-04 0.83935 0.15993 0.95911 -1.12959 
2000-01-05 2.80215 -0.10858 -1.62114 -0.20170 
2000-01-06 0.71670 -0.26707 1.36029 1.74254 
2000-01-07 -0.45749 0.22750 0.46291 -0.58431 
2000-01-10 -0.78702 0.44006 -0.36881 -0.13884 
2000-01-11 0.79577 -0.09198 0.14119 0.02668 
2000-01-12 -0.32297 0.62332 1.93595 0.78024 
2000-01-13 1.74683 -1.57738 -0.02134 0.11596 
2000-01-14 -0.55613 0.92145 -0.22832 1.56631 
2000-01-17 -0.55233 -0.28859 -1.18190 -0.80723 
2000-01-18 0.73274 0.24387 0.88146 -0.94490 
2000-01-19 0.56644 -0.49321 1.17584 -0.17585 
2000-01-20 1.56441 0.62331 -0.26904 0.11952 
2000-01-21 0.61834 0.17463 -1.62439 0.99103 
2000-01-24 0.86378 -0.68111 -0.15788 -0.16670 
2000-01-25 -1.12230 -0.16128 1.20401 1.08945 
2000-01-26 -0.63115 0.76077 -0.92795 -2.17118 
2000-01-27 1.37620 -1.10618 -0.37411 0.73780 
2000-01-28 -1.40276 1.98372 1.47096 -1.38043 
2000-01-31 0.54769 0.44100 -0.52775 0.84497 
2000-02-01 0.12443 0.32880 -0.71361 1.31778 
2000-02-02 -0.28986 -0.63931 0.88333 -2.58943 
2000-02-03 0.54408 1.17928 -0.26795 -0.51681 
2000-02-04 -0.07068 -1.29168 -0.59877 -1.45639 
2000-02-07 -0.65483 -0.29584 -0.02722 0.31270 
2000-02-08 -0.18529 -0.18701 -0.59132 -1.15239 
2000-02-09 -2.28496 0.36352 1.11596 0.02293 
2000-02-10 0.51054 0.97249 1.74501 0.20525 
2000-02-11 0.10100 0.27722 0.65843 1.73591 

In [12]: df[(df.values > 1.5).any(1)] 
Out[12]: 
      A  B  C  D  
2000-01-05 2.8021 -0.1086 -1.62114 -0.2017 
2000-01-06 0.7167 -0.2671 1.36029 1.7425 
2000-01-12 -0.3230 0.6233 1.93595 0.7802 
2000-01-13 1.7468 -1.5774 -0.02134 0.1160 
2000-01-14 -0.5561 0.9215 -0.22832 1.5663 
2000-01-20 1.5644 0.6233 -0.26904 0.1195 
2000-01-28 -1.4028 1.9837 1.47096 -1.3804 
2000-02-10 0.5105 0.9725 1.74501 0.2052 
2000-02-11 0.1010 0.2772 0.65843 1.7359 

múltiples condiciones tienen que combinarse usando & o | (y los paréntesis!):

In [13]: df[(df['A'] > 1) | (df['B'] < -1)] 
Out[13]: 
      A  B  C  D  
2000-01-05 2.80215 -0.1086 -1.62114 -0.2017 
2000-01-13 1.74683 -1.5774 -0.02134 0.1160 
2000-01-20 1.56441 0.6233 -0.26904 0.1195 
2000-01-27 1.37620 -1.1062 -0.37411 0.7378 
2000-02-04 -0.07068 -1.2917 -0.59877 -1.4564 

Estaría muy interesado en tener algún tipo de API de consulta para hacer este tipo de cosas más fácil

+1

Gracias de nuevo. Publicaremos futuras preguntas en la lista de correo. Pero por ahora, ¿y si quisieras hacer esto programáticamente? Tenías una lista de etiquetas de columna ... ¿cómo puedes meter eso en '|' ¿notación? P.ej. if 'labels = ['A', 'B', 'C', ... ']' – user248237dfsf

+0

Para aclarar: El enfoque 'any (1)' no funcionaría si tuviera otros valores en la tabla que no utilizó no quiero filtrar Supongamos que hay muchas columnas y que solo desea que el 'any' se aplique a un subconjunto de ellas (ya conoce las etiquetas del subconjunto). – user248237dfsf

5

Existen al menos algunos enfoques para acortar la sintaxis para esto en Pandas, hasta que obtenga una API de consulta completa por el camino (perhap) s Intentaré unirme al proyecto github y hacer esto es tiempo permitido y si nadie más ya ha comenzado).

Un método para acortar la sintaxis un poco es la siguiente:

inds = df.apply(lambda x: x["A"]>10 and x["B"]<5, axis=1) 
print df[inds].to_string() 

Para resolver completamente este, que uno puede necesitar para construir algo así como el SQL seleccionar y donde cláusulas en los pandas. Esto no es trivial en absoluto, pero una punzada que creo que podría funcionar para esto es utilizar el módulo integrado en Python operator. Esto le permite tratar cosas más grandes que funciones en lugar de símbolos. Por lo que podría hacer lo siguiente:

def pandas_select(dataframe, select_dict): 

    inds = dataframe.apply(lambda x: reduce(lambda v1,v2: v1 and v2, 
          [elem[0](x[key], elem[1]) 
          for key,elem in select_dict.iteritems()]), axis=1) 
    return dataframe[inds] 

A continuación, un ejemplo de prueba como la suya habría que hacer lo siguiente:

import operator 
select_dict = { 
       "A":(operator.gt,10), 
       "B":(operator.lt,5)     
       } 

print pandas_select(df, select_dict).to_string() 

se puede acortar la sintaxis aún más por cualquiera de edificio en más argumentos a pandas_select a maneja los diferentes operadores lógicos comunes automáticamente, o importándolos en el espacio de nombres con nombres más cortos.

Tenga en cuenta que la función pandas_select anterior sólo funciona con cadenas lógicas y de las limitaciones. Tendría que modificarlo para obtener un comportamiento lógico diferente. O utilizar not y De Morgan de las Leyes.

+0

Si tengo una lista ['Alice', 'Bob', 'Carl'], ¿cómo puedo generar el diccionario para seleccionar elementos donde dataframe ['A'] está en mi lista? –

+1

Si la lista es 'a = ['Alice', 'Bob', 'Carl']' y el marco de datos general se llama 'df', entonces puede hacer esto:' df [df.A.isin (a) ] 'y sub-seleccionará los índices de filas donde la condición de membresía establecida es verdadera para los elementos de la columna' A '. Expandir el mini lenguaje específico de dominio que hice anteriormente para expresar lógicos para tener esta opción con sintaxis simple probablemente sea una tarea incómoda. – ely

+0

vea también el próximo método de consulta (pandas 0.13): http://pandas.pydata.org/pandas-docs/dev/indexing.html?highlight=query#the-query-method-experimental y también http : //stackoverflow.com/questions/18521037/pandas-iterative-filtering-a-dataframes-rows – RuiDC

1

Se ha añadido una función de consulta a Pandas ya que esta pregunta fue hecha y respondida. Un ejemplo se da a continuación.

Dada esta trama de datos de muestra:

periods = 8 
dates = pd.date_range('20170101', periods=periods) 
rand_df = pd.DataFrame(np.random.randn(periods,4), index=dates, 
     columns=list('ABCD')) 

La sintaxis de la consulta de la siguiente manera le permitirá utilizar varios filtros, como una cláusula "WHERE" en una instrucción de selección.

rand_df.query("A < 0 or B < 0") 

Véase el Pandas documentation para obtener detalles adicionales.

Cuestiones relacionadas