python - para - seleccionar columnas en pandas
seleccionando a través de múltiples columnas con pandas de pitón? (3)
Tengo un marco de datos df
en pandas que se construyó 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 único, ya que cada fila tiene un valor único para esa columna utilizada para la indexación).
¿Cómo puedo seleccionar las filas de mi marco de datos en función de un filtro "complejo" aplicado a múltiples columnas? Puedo seleccionar fácilmente la porción del marco de datos donde la columna colA
es mayor que 10, por ejemplo:
df_greater_than10 = df[df["colA"] > 10]
Pero, ¿y si quisiera un filtro como: seleccione 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 estos en pandas? Gracias.
Hay al menos algunos enfoques para acortar la sintaxis para esto en Pandas, hasta que obtenga una API de consulta completa más adelante (quizás intente unirme al proyecto github y hacer esto es tiempo permitido y si nadie más ya tiene empezado).
Un método para acortar un poco la sintaxis se da a continuación:
inds = df.apply(lambda x: x["A"]>10 and x["B"]<5, axis=1)
print df[inds].to_string()
Para resolverlo completamente, uno necesitaría construir algo así como las cláusulas SQL select y where en Pandas. Esto no es para nada trivial, pero una puñalada que creo que podría funcionar para esto es usar el módulo integrado del operator
Python. Esto le permite tratar cosas más grandes que funciones en lugar de símbolos. Entonces 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 suyo 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 aún más la sintaxis construyendo más argumentos para que pandas_select
maneje automáticamente los diferentes operadores lógicos comunes o importándolos en el espacio de nombres con nombres más cortos.
Tenga en cuenta que la función pandas_select
anterior solo funciona con cadenas lógicas y de restricciones. Tendría que modificarlo para obtener un comportamiento lógico diferente. O use not
y las Leyes de DeMorgan.
Se agregó una característica de consulta a Pandas desde que se hizo y respondió esta pregunta. Un ejemplo se da a continuación.
Dado este marco 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á usar varios filtros, como una cláusula "WHERE" en una declaración de selección.
rand_df.query("A < 0 or B < 0")
Consulte la documentación de Pandas para obtener detalles adicionales.
Te animo a que plantees estas preguntas en la lista de correo , pero en cualquier caso, sigue siendo una aventura de muy bajo nivel trabajando con las matrices subyacentes de NumPy. Por ejemplo, para seleccionar filas donde el valor de cualquier columna sea superior, digamos, 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
Se deben combinar varias condiciones usando &
o |
(y 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 facilitar este tipo de cosas