¿Seleccionando a través de múltiples columnas con pandas python?

Tengo un df dataframe en pandas que fue construido usando pandas.read_table desde un archivo csv. El dataframe tiene varias columnas y está indexado por una de las columnas (que es única, en el sentido de que cada fila tiene un valor único para esa columna utilizada para la indexación).

¿Cómo puedo seleccionar filas de mi dataframe según un filtro “complejo” aplicado a varias columnas? Puedo seleccionar fácilmente la porción del dataframe donde la columna colA es mayor que 10 por ejemplo:

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

Pero, ¿qué sucede si quisiera un filtro como: seleccionar la porción de df donde cualquiera de las columnas es mayor que 10?

¿O donde el valor para colA es mayor que 10 pero el valor para colB es menor que 5?

¿Cómo se implementan en pandas? Gracias.

Lo aliento a plantear estas preguntas en la lista de correo , pero en cualquier caso, sigue siendo un asunto de muy bajo nivel trabajando con las matrices de NumPy subyacentes. Por ejemplo, para seleccionar filas donde el valor en cualquier columna exceda, por ejemplo, 1.5 en este ejemplo:

 In [11]: df Out[11]: ABCD 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]: ABCD 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 

Se deben combinar varias condiciones usando & o | (y paréntesis!):

 In [13]: df[(df['A'] > 1) | (df['B'] < -1)] Out[13]: ABCD 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 

Me interesaría mucho tener algún tipo de API de consulta para facilitar este tipo de cosas

Hay al menos algunos enfoques para acortar la syntax para esto en Pandas, hasta que obtenga una API de consulta completa en el futuro (tal vez intentaré unirme al proyecto github y hacer esto si el tiempo lo permite y si nadie más ya lo ha hecho). empezado).

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

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

Para resolver esto completamente, uno necesitaría construir algo como la selección de SQL y las cláusulas donde se encuentran en Pandas. Esto no es en absoluto trivial, pero una puñalada que creo que podría funcionar para esto es usar el módulo incorporado del operator Python. Esto le permite tratar las cosas como mayor que como funciones en lugar de símbolos. Así que podrías 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] 

Entonces un ejemplo de prueba como el tuyo sería hacer lo siguiente:

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

Puede acortar la syntax aún más mediante la creación de más argumentos en pandas_select para manejar los diferentes operadores lógicos comunes de manera automática, o importándolos al espacio de nombres con nombres más cortos.

Tenga en cuenta que la función pandas_select anterior solo funciona con cadenas de restricciones lógicas. Tendrías que modificarlo para obtener un comportamiento lógico diferente. O utilizar not y las leyes de DeMorgan.

Se ha agregado una función de consulta a Pandas desde que se hizo esta pregunta y se respondió. Un ejemplo se da a continuación.

Dado este dataframe 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 siguiente syntax de consulta le permitirá utilizar varios filtros, como una cláusula “WHERE” en una statement de selección.

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

Consulte la documentación de Pandas para más detalles.