¿Cómo selecciono filas de un DataFrame según los valores de columna?
Frecuentes
Visto 5,256 equipos
16 Respuestas
5894
Para seleccionar filas cuyo valor de columna es igual a un escalar, some_value
, Utilizar ==
:
df.loc[df['column_name'] == some_value]
Para seleccionar filas cuyo valor de columna está en un iterable, some_values
, Utilizar isin
:
df.loc[df['column_name'].isin(some_values)]
Combinar múltiples condiciones con &
:
df.loc[(df['column_name'] >= A) & (df['column_name'] <= B)]
Tenga en cuenta los paréntesis. Debido a Python reglas de precedencia del operador, &
se une más fuerte que <=
y >=
. Por lo tanto, los paréntesis en el último ejemplo son necesarios. sin los paréntesis
df['column_name'] >= A & df['column_name'] <= B
se analiza como
df['column_name'] >= (A & df['column_name']) <= B
lo que resulta en un El valor de verdad de una serie es un error ambiguo.
Para seleccionar filas cuyo valor de columna no es igual some_value
, Utilizar !=
:
df.loc[df['column_name'] != some_value]
isin
devuelve una serie booleana, por lo que para seleccionar filas cuyo valor es no in some_values
, niega la Serie booleana usando ~
:
df.loc[~df['column_name'].isin(some_values)]
Por ejemplo,
import pandas as pd
import numpy as np
df = pd.DataFrame({'A': 'foo bar foo bar foo bar foo foo'.split(),
'B': 'one one two three two two one three'.split(),
'C': np.arange(8), 'D': np.arange(8) * 2})
print(df)
# A B C D
# 0 foo one 0 0
# 1 bar one 1 2
# 2 foo two 2 4
# 3 bar three 3 6
# 4 foo two 4 8
# 5 bar two 5 10
# 6 foo one 6 12
# 7 foo three 7 14
print(df.loc[df['A'] == 'foo'])
los rendimientos
A B C D
0 foo one 0 0
2 foo two 2 4
4 foo two 4 8
6 foo one 6 12
7 foo three 7 14
Si tiene varios valores que desea incluir, póngalos en una lista (o más generalmente, cualquier iterable) y use isin
:
print(df.loc[df['B'].isin(['one','three'])])
los rendimientos
A B C D
0 foo one 0 0
1 bar one 1 2
3 bar three 3 6
6 foo one 6 12
7 foo three 7 14
Tenga en cuenta, sin embargo, que si desea hacer esto muchas veces, es más eficiente crear primero un índice y luego usar df.loc
:
df = df.set_index(['B'])
print(df.loc['one'])
los rendimientos
A C D
B
one foo 0 0
one bar 1 2
one foo 6 12
o, para incluir múltiples valores del uso del índice df.index.isin
:
df.loc[df.index.isin(['one','two'])]
los rendimientos
A C D
B
one foo 0 0
one bar 1 2
two foo 2 4
two foo 4 8
two bar 5 10
one foo 6 12
Respondido el 18 de enero de 19 a las 02:01
709
Hay varias formas de seleccionar filas de un dataframe de Pandas:
- indexación booleana (
df[df['col'] == value
]) - Indexación posicional (
df.iloc[...]
) - Etiqueta de indexación (
df.xs(...)
) df.query(...)
API
A continuación te muestro ejemplos de cada uno, con consejos sobre cuándo usar ciertas técnicas. Supongamos que nuestro criterio es columna 'A'
== 'foo'
(Nota sobre el rendimiento: para cada tipo base, podemos simplificar las cosas usando la API de Pandas o podemos aventurarnos fuera de la API, generalmente en NumPy, y acelerar las cosas).
Preparar
Lo primero que necesitaremos es identificar una condición que actuará como nuestro criterio para seleccionar filas. Empezaremos con el caso del OP column_name == some_value
e incluyen algunos otros casos de uso comunes.
Tomando prestado de @unutbu:
import pandas as pd, numpy as np
df = pd.DataFrame({'A': 'foo bar foo bar foo bar foo foo'.split(),
'B': 'one one two three two two one three'.split(),
'C': np.arange(8), 'D': np.arange(8) * 2})
1. Indexación booleana
... La indexación booleana requiere encontrar el verdadero valor de cada fila 'A'
columna siendo igual a 'foo'
, luego usa esos valores de verdad para identificar qué filas conservar. Por lo general, nombraríamos esta serie, una matriz de valores de verdad, mask
. Lo haremos aquí también.
mask = df['A'] == 'foo'
Luego podemos usar esta máscara para dividir o indexar el marco de datos
df[mask]
A B C D
0 foo one 0 0
2 foo two 2 4
4 foo two 4 8
6 foo one 6 12
7 foo three 7 14
Esta es una de las formas más simples de realizar esta tarea y si el rendimiento o la intuición no son un problema, este debería ser su método elegido. Sin embargo, si el rendimiento es una preocupación, es posible que desee considerar una forma alternativa de crear el mask
.
2. Indexación posicional
Indexación posicional (df.iloc[...]
) tiene sus casos de uso, pero este no es uno de ellos. Para identificar dónde cortar, primero debemos realizar el mismo análisis booleano que hicimos anteriormente. Esto nos deja realizando un paso adicional para lograr la misma tarea.
mask = df['A'] == 'foo'
pos = np.flatnonzero(mask)
df.iloc[pos]
A B C D
0 foo one 0 0
2 foo two 2 4
4 foo two 4 8
6 foo one 6 12
7 foo three 7 14
3. Indexación de etiquetas
Disquera la indexación puede ser muy útil, pero en este caso, nuevamente estamos haciendo más trabajo sin ningún beneficio
df.set_index('A', append=True, drop=False).xs('foo', level=1)
A B C D
0 foo one 0 0
2 foo two 2 4
4 foo two 4 8
6 foo one 6 12
7 foo three 7 14
4. df.query()
API
pd.DataFrame.query
es una forma muy elegante/intuitiva de realizar esta tarea, pero suele ser más lenta. Sin embargo, si presta atención a los tiempos a continuación, para datos grandes, la consulta es muy eficiente. Más que el enfoque estándar y de magnitud similar a mi mejor sugerencia.
df.query('A == "foo"')
A B C D
0 foo one 0 0
2 foo two 2 4
4 foo two 4 8
6 foo one 6 12
7 foo three 7 14
Mi preferencia es usar el Boolean
mask
Se pueden realizar mejoras reales modificando la forma en que creamos nuestros Boolean
mask
.
mask
alternativa 1
Use la matriz NumPy subyacente y renuncie a la sobrecarga de crear otra pd.Series
mask = df['A'].values == 'foo'
Mostraré pruebas de tiempo más completas al final, pero solo eche un vistazo a las ganancias de rendimiento que obtenemos usando el marco de datos de muestra. En primer lugar, observamos la diferencia en la creación de la mask
%timeit mask = df['A'].values == 'foo'
%timeit mask = df['A'] == 'foo'
5.84 µs ± 195 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
166 µs ± 4.45 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
Evaluando el mask
con la matriz NumPy es ~ 30 veces más rápido. Esto se debe en parte a que la evaluación de NumPy suele ser más rápida. También se debe en parte a la falta de gastos generales necesarios para construir un índice y su correspondiente pd.Series
objeto.
A continuación, veremos el tiempo para cortar con una mask
contra el otro.
mask = df['A'].values == 'foo'
%timeit df[mask]
mask = df['A'] == 'foo'
%timeit df[mask]
219 µs ± 12.3 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
239 µs ± 7.03 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
Las ganancias de rendimiento no son tan pronunciadas. Veremos si esto se mantiene en pruebas más sólidas.
mask
alternativa 2
Podríamos haber reconstruido el marco de datos también. Hay una gran advertencia al reconstruir un marco de datos: debe cuidar el dtypes
al hacerlo!
En lugar de df[mask]
nosotros haremos esto
pd.DataFrame(df.values[mask], df.index[mask], df.columns).astype(df.dtypes)
Si el marco de datos es de tipo mixto, que es nuestro ejemplo, cuando obtengamos df.values
la matriz resultante es de dtype
object
y en consecuencia, todas las columnas del nuevo marco de datos serán de dtype
object
. Requiriendo así la astype(df.dtypes)
y matando cualquier ganancia potencial de rendimiento.
%timeit df[m]
%timeit pd.DataFrame(df.values[mask], df.index[mask], df.columns).astype(df.dtypes)
216 µs ± 10.4 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
1.43 ms ± 39.6 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
Sin embargo, si el marco de datos no es de tipo mixto, esta es una forma muy útil de hacerlo.
Dado que los
np.random.seed([3,1415])
d1 = pd.DataFrame(np.random.randint(10, size=(10, 5)), columns=list('ABCDE'))
d1
A B C D E
0 0 2 7 3 8
1 7 0 6 8 6
2 0 2 0 4 9
3 7 3 2 4 3
4 3 6 7 7 4
5 5 3 7 5 9
6 8 7 6 4 7
7 6 2 6 6 5
8 2 8 7 5 8
9 4 7 6 1 5
%%timeit
mask = d1['A'].values == 7
d1[mask]
179 µs ± 8.73 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
Versus
%%timeit
mask = d1['A'].values == 7
pd.DataFrame(d1.values[mask], d1.index[mask], d1.columns)
87 µs ± 5.12 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
Reducimos el tiempo a la mitad.
mask
alternativa 3
@unutbu también nos muestra cómo usar pd.Series.isin
para dar cuenta de cada elemento de df['A']
estar en un conjunto de valores. Esto se evalúa como lo mismo si nuestro conjunto de valores es un conjunto de un valor, a saber 'foo'
. Pero también se generaliza para incluir conjuntos de valores más grandes si es necesario. Resulta que esto sigue siendo bastante rápido a pesar de que es una solución más general. La única pérdida real está en la intuición para aquellos que no están familiarizados con el concepto.
mask = df['A'].isin(['foo'])
df[mask]
A B C D
0 foo one 0 0
2 foo two 2 4
4 foo two 4 8
6 foo one 6 12
7 foo three 7 14
Sin embargo, como antes, podemos utilizar NumPy para mejorar el rendimiento sin sacrificar prácticamente nada. usaremos np.in1d
mask = np.in1d(df['A'].values, ['foo'])
df[mask]
A B C D
0 foo one 0 0
2 foo two 2 4
4 foo two 4 8
6 foo one 6 12
7 foo three 7 14
Sincronización
Incluiré otros conceptos mencionados en otras publicaciones también como referencia.
Código a continuación
Cada visión de conjunto en esta tabla representa un marco de datos de longitud diferente sobre el cual probamos cada función. Cada columna muestra el tiempo relativo empleado, con la función más rápida dada un índice base de 1.0
.
res.div(res.min())
10 30 100 300 1000 3000 10000 30000
mask_standard 2.156872 1.850663 2.034149 2.166312 2.164541 3.090372 2.981326 3.131151
mask_standard_loc 1.879035 1.782366 1.988823 2.338112 2.361391 3.036131 2.998112 2.990103
mask_with_values 1.010166 1.000000 1.005113 1.026363 1.028698 1.293741 1.007824 1.016919
mask_with_values_loc 1.196843 1.300228 1.000000 1.000000 1.038989 1.219233 1.037020 1.000000
query 4.997304 4.765554 5.934096 4.500559 2.997924 2.397013 1.680447 1.398190
xs_label 4.124597 4.272363 5.596152 4.295331 4.676591 5.710680 6.032809 8.950255
mask_with_isin 1.674055 1.679935 1.847972 1.724183 1.345111 1.405231 1.253554 1.264760
mask_with_in1d 1.000000 1.083807 1.220493 1.101929 1.000000 1.000000 1.000000 1.144175
Notarás que los tiempos más rápidos parecen estar compartidos entre mask_with_values
y mask_with_in1d
.
res.T.plot(loglog=True)
clave
def mask_standard(df):
mask = df['A'] == 'foo'
return df[mask]
def mask_standard_loc(df):
mask = df['A'] == 'foo'
return df.loc[mask]
def mask_with_values(df):
mask = df['A'].values == 'foo'
return df[mask]
def mask_with_values_loc(df):
mask = df['A'].values == 'foo'
return df.loc[mask]
def query(df):
return df.query('A == "foo"')
def xs_label(df):
return df.set_index('A', append=True, drop=False).xs('foo', level=-1)
def mask_with_isin(df):
mask = df['A'].isin(['foo'])
return df[mask]
def mask_with_in1d(df):
mask = np.in1d(df['A'].values, ['foo'])
return df[mask]
Pruebas
res = pd.DataFrame(
index=[
'mask_standard', 'mask_standard_loc', 'mask_with_values', 'mask_with_values_loc',
'query', 'xs_label', 'mask_with_isin', 'mask_with_in1d'
],
columns=[10, 30, 100, 300, 1000, 3000, 10000, 30000],
dtype=float
)
for j in res.columns:
d = pd.concat([df] * j, ignore_index=True)
for i in res.index:a
stmt = '{}(d)'.format(i)
setp = 'from __main__ import d, {}'.format(i)
res.at[i, j] = timeit(stmt, setp, number=50)
Tiempo especial
Mirando el caso especial cuando tenemos un solo no objeto dtype
para todo el marco de datos.
Código a continuación
spec.div(spec.min())
10 30 100 300 1000 3000 10000 30000
mask_with_values 1.009030 1.000000 1.194276 1.000000 1.236892 1.095343 1.000000 1.000000
mask_with_in1d 1.104638 1.094524 1.156930 1.072094 1.000000 1.000000 1.040043 1.027100
reconstruct 1.000000 1.142838 1.000000 1.355440 1.650270 2.222181 2.294913 3.406735
Resulta que la reconstrucción no vale la pena más allá de unos cientos de filas.
spec.T.plot(loglog=True)
clave
np.random.seed([3,1415])
d1 = pd.DataFrame(np.random.randint(10, size=(10, 5)), columns=list('ABCDE'))
def mask_with_values(df):
mask = df['A'].values == 'foo'
return df[mask]
def mask_with_in1d(df):
mask = np.in1d(df['A'].values, ['foo'])
return df[mask]
def reconstruct(df):
v = df.values
mask = np.in1d(df['A'].values, ['foo'])
return pd.DataFrame(v[mask], df.index[mask], df.columns)
spec = pd.DataFrame(
index=['mask_with_values', 'mask_with_in1d', 'reconstruct'],
columns=[10, 30, 100, 300, 1000, 3000, 10000, 30000],
dtype=float
)
Pruebas
for j in spec.columns:
d = pd.concat([df] * j, ignore_index=True)
for i in spec.index:
stmt = '{}(d)'.format(i)
setp = 'from __main__ import d, {}'.format(i)
spec.at[i, j] = timeit(stmt, setp, number=50)
Respondido 04 Feb 21, 16:02
utilizan el df['A'].values == 'foo'
apper FutureWarning: error en la comparación de elementos; devolviendo escalar en su lugar, pero en el futuro realizará una comparación por elementos: junyu
335
tl; dr
Los pandas equivalentes a
select * from table where column_name = some_value
is
table[table.column_name == some_value]
Múltiples condiciones:
table[(table.column_name == some_value) | (table.column_name2 == some_value2)]
or
table.query('column_name == some_value | column_name2 == some_value2')
Ejemplo de código
import pandas as pd
# Create data set
d = {'foo':[100, 111, 222],
'bar':[333, 444, 555]}
df = pd.DataFrame(d)
# Full dataframe:
df
# Shows:
# bar foo
# 0 333 100
# 1 444 111
# 2 555 222
# Output only the row(s) in df where foo is 222:
df[df.foo == 222]
# Shows:
# bar foo
# 2 555 222
En el código anterior es la línea df[df.foo == 222]
que da las filas basadas en el valor de la columna, 222
en este caso.
Múltiples condiciones también son posibles:
df[(df.foo == 222) | (df.bar == 444)]
# bar foo
# 1 444 111
# 2 555 222
Pero en ese punto yo recomendaría usar el pregunta función, ya que es menos detallada y produce el mismo resultado:
df.query('foo == 222 | bar == 444')
Respondido 05 Oct 20, 19:10
85
Encuentro que la sintaxis de las respuestas anteriores es redundante y difícil de recordar. Los pandas introdujeron el query()
método en v0.13 y lo prefiero mucho. Para tu pregunta, podrías hacer df.query('col == val')
.
Reproducido de El método query() (experimental):
In [167]: n = 10
In [168]: df = pd.DataFrame(np.random.rand(n, 3), columns=list('abc'))
In [169]: df
Out[169]:
a b c
0 0.687704 0.582314 0.281645
1 0.250846 0.610021 0.420121
2 0.624328 0.401816 0.932146
3 0.011763 0.022921 0.244186
4 0.590198 0.325680 0.890392
5 0.598892 0.296424 0.007312
6 0.634625 0.803069 0.123872
7 0.924168 0.325076 0.303746
8 0.116822 0.364564 0.454607
9 0.986142 0.751953 0.561512
# pure python
In [170]: df[(df.a < df.b) & (df.b < df.c)]
Out[170]:
a b c
3 0.011763 0.022921 0.244186
8 0.116822 0.364564 0.454607
# query
In [171]: df.query('(a < b) & (b < c)')
Out[171]:
a b c
3 0.011763 0.022921 0.244186
8 0.116822 0.364564 0.454607
También puede acceder a las variables en el entorno anteponiendo un @
.
exclude = ('red', 'orange')
df.query('color not in @exclude')
Respondido el 16 de Septiembre de 22 a las 22:09
65
Más flexibilidad usando .query
con pandas >= 0.25.0:
Como pandas >= 0.25.0 podemos usar el query
método para filtrar marcos de datos con métodos pandas e incluso nombres de columnas que tienen espacios. Normalmente, los espacios en los nombres de las columnas darían un error, pero ahora podemos resolverlo usando un acento grave (`) - ver GitHub:
# Example dataframe
df = pd.DataFrame({'Sender email':['ex@example.com', "reply@shop.com", "buy@shop.com"]})
Sender email
0 ex@example.com
1 reply@shop.com
2 buy@shop.com
Usar .query
con metodo str.endswith
:
df.query('`Sender email`.str.endswith("@shop.com")')
Salida
Sender email
1 reply@shop.com
2 buy@shop.com
También podemos usar variables locales prefijándolas con un @
en nuestra consulta:
domain = 'shop.com'
df.query('`Sender email`.str.endswith(@domain)')
Salida
Sender email
1 reply@shop.com
2 buy@shop.com
respondido 28 mar '22, 12:03
37
Para seleccionar solo columnas específicas de varias columnas para un valor dado en Pandas:
select col_name1, col_name2 from table where column_name = some_value.
Opciones loc
:
df.loc[df['column_name'] == some_value, [col_name1, col_name2]]
or query
:
df.query('column_name == some_value')[[col_name1, col_name2]]
Respondido el 05 de Septiembre de 21 a las 09:09
33
En versiones más nuevas de Pandas, inspiradas en la documentación (Ver datos):
df[df["colume_name"] == some_value] #Scalar, True/False..
df[df["colume_name"] == "some_value"] #String
Combine múltiples condiciones poniendo la cláusula entre paréntesis, ()
, y combinándolos con &
y |
(y/o). Como esto:
df[(df["colume_name"] == "some_value1") & (pd[pd["colume_name"] == "some_value2"])]
Otros filtros
pandas.notna(df["colume_name"]) == True # Not NaN
df['colume_name'].str.contains("text") # Search for "text"
df['colume_name'].str.lower().str.contains("text") # Search for "text", after converting to lowercase
Respondido 08 Feb 21, 15:02
31
Se pueden lograr resultados más rápidos utilizando numpy donde.
Por ejemplo, con configuración de unubtu -
In [76]: df.iloc[np.where(df.A.values=='foo')]
Out[76]:
A B C D
0 foo one 0 0
2 foo two 2 4
4 foo two 4 8
6 foo one 6 12
7 foo three 7 14
Comparaciones de tiempo:
In [68]: %timeit df.iloc[np.where(df.A.values=='foo')] # fastest
1000 loops, best of 3: 380 µs per loop
In [69]: %timeit df.loc[df['A'] == 'foo']
1000 loops, best of 3: 745 µs per loop
In [71]: %timeit df.loc[df['A'].isin(['foo'])]
1000 loops, best of 3: 562 µs per loop
In [72]: %timeit df[df.A=='foo']
1000 loops, best of 3: 796 µs per loop
In [74]: %timeit df.query('(A=="foo")') # slowest
1000 loops, best of 3: 1.71 ms per loop
Respondido 03 Oct 17, 17:10
29
Aquí hay un ejemplo simple.
from pandas import DataFrame
# Create data set
d = {'Revenue':[100,111,222],
'Cost':[333,444,555]}
df = DataFrame(d)
# mask = Return True when the value in column "Revenue" is equal to 111
mask = df['Revenue'] == 111
print mask
# Result:
# 0 False
# 1 True
# 2 False
# Name: Revenue, dtype: bool
# Select * FROM df WHERE Revenue = 111
df[mask]
# Result:
# Cost Revenue
# 1 444 111
Respondido el 13 de junio de 13 a las 12:06
19
Para añadir: También puedes hacer df.groupby('column_name').get_group('column_desired_value').reset_index()
para crear un nuevo marco de datos con una columna específica que tenga un valor particular. P.ej,
import pandas as pd
df = pd.DataFrame({'A': 'foo bar foo bar foo bar foo foo'.split(),
'B': 'one one two three two two one three'.split()})
print("Original dataframe:")
print(df)
b_is_two_dataframe = pd.DataFrame(df.groupby('B').get_group('two').reset_index()).drop('index', axis = 1)
#NOTE: the final drop is to remove the extra index column returned by groupby object
print('Sub dataframe where B is two:')
print(b_is_two_dataframe)
Ejecutar esto da:
Original dataframe:
A B
0 foo one
1 bar one
2 foo two
3 bar three
4 foo two
5 bar two
6 foo one
7 foo three
Sub dataframe where B is two:
A B
0 foo two
1 foo two
2 bar two
Respondido el 16 de Septiembre de 22 a las 23:09
11
También puedes usar .apply:
df.apply(lambda row: row[df['B'].isin(['one','three'])])
En realidad, funciona por filas (es decir, aplica la función a cada fila).
La salida es
A B C D
0 foo one 0 0
1 bar one 1 2
3 bar three 3 6
6 foo one 6 12
7 foo three 7 14
Los resultados son los mismos que los mencionados por @unutbu
df[[df['B'].isin(['one','three'])]]
Respondido el 07 de diciembre de 18 a las 17:12
5
Si desea realizar consultas en su marco de datos repetidamente y la velocidad es importante para usted, lo mejor es convertir su marco de datos en diccionario y, al hacerlo, puede realizar consultas miles de veces más rápido.
my_df = df.set_index(column_name)
my_dict = my_df.to_dict('index')
Después de hacer el diccionario my_dict, puede pasar por:
if some_value in my_dict.keys():
my_result = my_dict[some_value]
Si tiene valores duplicados en column_name, no puede crear un diccionario. pero puedes usar:
my_result = my_df.loc[some_value]
respondido 27 nov., 21:17
3
Declaraciones SQL en DataFrames para seleccionar filas usando DuckDB
Con PatoDB podemos consultar pandas DataFrames con declaraciones SQL, en un forma de alto rendimiento.
Ya que la pregunta es ¿Cómo selecciono filas de un DataFrame según los valores de columna?, y el ejemplo en la pregunta es una consulta SQL, esta respuesta parece lógica en este tema.
Ejemplo:
In [1]: import duckdb
In [2]: import pandas as pd
In [3]: con = duckdb.connect()
In [4]: df = pd.DataFrame({"A": range(11), "B": range(11, 22)})
In [5]: df
Out[5]:
A B
0 0 11
1 1 12
2 2 13
3 3 14
4 4 15
5 5 16
6 6 17
7 7 18
8 8 19
9 9 20
10 10 21
In [6]: results = con.execute("SELECT * FROM df where A > 2").df()
In [7]: results
Out[7]:
A B
0 3 14
1 4 15
2 5 16
3 6 17
4 7 18
5 8 19
6 9 20
7 10 21
Respondido el 16 de Septiembre de 22 a las 23:09
2
Puedes usar loc
(corchetes) con una función:
# Series
s = pd.Series([1, 2, 3, 4])
s.loc[lambda x: x > 1]
# s[lambda x: x > 1]
Salida:
1 2
2 3
3 4
dtype: int64
or
# DataFrame
df = pd.DataFrame({'A': [1, 2, 3], 'B': [10, 20, 30]})
df.loc[lambda x: x['A'] > 1]
# df[lambda x: x['A'] > 1]
Salida:
A B
1 2 20
2 3 30
La ventaja de este método es que puede encadenar la selección con operaciones anteriores. Por ejemplo:
df.mul(2).loc[lambda x: x['A'] > 3, 'B']
# (df * 2).loc[lambda x: x['A'] > 3, 'B']
vs
df_temp = df * 2
df_temp.loc[df_temp['A'] > 3, 'B']
Salida:
1 40
2 60
Name: B, dtype: int64
Respondido 02 ago 22, 21:08
1
Grandes respuestas. Sólo, cuando el el tamaño del marco de datos se acerca a millones de filas, muchos de los métodos tienden a tomar años cuando se usan df[df['col']==val]
. Quería tener todos los valores posibles de "otra_columna" que correspondan a valores específicos en "alguna_columna" (en este caso en un diccionario). Esto funcionó y rápido.
s=datetime.datetime.now()
my_dict={}
for i, my_key in enumerate(df['some_column'].values):
if i%100==0:
print(i) # to see the progress
if my_key not in my_dict.keys():
my_dict[my_key]={}
my_dict[my_key]['values']=[df.iloc[i]['another_column']]
else:
my_dict[my_key]['values'].append(df.iloc[i]['another_column'])
e=datetime.datetime.now()
print('operation took '+str(e-s)+' seconds')```
Respondido 16 Feb 22, 21:02
1
1. Instalar numexpr
acelerar query()
llamadas
La documentación de los pandas. recomienda instalar numexpr para acelerar el cálculo numérico cuando se utiliza query()
. Utilizar pip install numexpr
(o conda
, sudo
etc. dependiendo de su entorno) para instalarlo.
Para marcos de datos más grandes (donde el rendimiento realmente importa), df.query()
a numexpr
El motor funciona mucho más rápido que df[mask]
. En particular, funciona mejor para los siguientes casos.
Operadores lógicos y/o de comparación en columnas de cadenas
Si una columna de cadenas se compara con otra(s) cadena(s) y se van a seleccionar filas coincidentes, incluso para una sola operación de comparación, query()
funciona más rápido que df[mask]
. Por ejemplo, para un marco de datos con filas de 80k, es un 30% más rápido1 y para un marco de datos con filas de 800k, es un 60% más rápido.2
df[df.A == 'foo']
df.query("A == 'foo'") # <--- performs 30%-60% faster
Esta brecha aumenta a medida que aumenta el número de operaciones (si se encadenan 4 comparaciones df.query()
es 2-2.3 veces más rápido que df[mask]
)1,2 y/o la longitud de la trama de datos aumenta.2
Múltiples operaciones en columnas numéricas
Si es necesario calcular múltiples operaciones aritméticas, lógicas o de comparación para crear una máscara booleana para filtrar df
, query()
realiza más rápido. Por ejemplo, para un marco con 80k filas, es un 20 % más rápido1 y para un marco con filas de 800k, es 2 veces más rápido.2
df[(df.B % 5) **2 < 0.1]
df.query("(B % 5) **2 < 0.1") # <--- performs 20%-100% faster.
Esta brecha en el rendimiento aumenta a medida que aumenta el número de operaciones y/o aumenta la longitud del marco de datos.2
El siguiente gráfico muestra cómo funcionan los métodos a medida que aumenta la longitud del marco de datos.3
2. Acceso .values
para llamar a los métodos de pandas dentro query()
Numexpr
actualmente apoya solo lógico (&
, |
, ~
), comparación (==
, >
, <
, >=
, <=
, !=
) y operadores aritméticos básicos (+
, -
, *
, /
, **
, %
).
Por ejemplo, no admite la división de enteros (//
). Sin embargo, llamando al método pandas equivalente (floordiv()
) y accediendo a la values
atributo en la Serie resultante hace numexpr
evaluar su matriz numpy subyacente y query()
obras. o ajuste engine
parámetro para 'python'
También funciona.
df.query('B.floordiv(2).values <= 3') # or
df.query('B.floordiv(2).le(3).values') # or
df.query('B.floordiv(2).le(3)', engine='python')
Lo mismo aplica para ErfanLas llamadas a métodos sugeridos también. El código en su respuesta escupe TypeError tal como está (a partir de Pandas 1.3.4) para numexpr
motor pero accediendo .values
atributo hace que funcione.
df.query('`Sender email`.str.endswith("@shop.com")') # <--- TypeError
df.query('`Sender email`.str.endswith("@shop.com").values') # OK
1: Código de referencia usando un marco con 80k filas
import numpy as np
df = pd.DataFrame({'A': 'foo bar foo baz foo bar foo foo'.split()*10000,
'B': np.random.rand(80000)})
%timeit df[df.A == 'foo']
# 8.5 ms ± 104.5 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit df.query("A == 'foo'")
# 6.36 ms ± 95.7 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit df[((df.A == 'foo') & (df.A != 'bar')) | ((df.A != 'baz') & (df.A != 'buz'))]
# 29 ms ± 554 µs per loop (mean ± std. dev. of 10 runs, 100 loops each)
%timeit df.query("A == 'foo' & A != 'bar' | A != 'baz' & A != 'buz'")
# 16 ms ± 339 µs per loop (mean ± std. dev. of 10 runs, 100 loops each)
%timeit df[(df.B % 5) **2 < 0.1]
# 5.35 ms ± 37.6 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit df.query("(B % 5) **2 < 0.1")
# 4.37 ms ± 46.3 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
2: Código de referencia usando un marco con 800k filas
df = pd.DataFrame({'A': 'foo bar foo baz foo bar foo foo'.split()*100000,
'B': np.random.rand(800000)})
%timeit df[df.A == 'foo']
# 87.9 ms ± 873 µs per loop (mean ± std. dev. of 10 runs, 100 loops each)
%timeit df.query("A == 'foo'")
# 54.4 ms ± 726 µs per loop (mean ± std. dev. of 10 runs, 100 loops each)
%timeit df[((df.A == 'foo') & (df.A != 'bar')) | ((df.A != 'baz') & (df.A != 'buz'))]
# 310 ms ± 3.4 ms per loop (mean ± std. dev. of 10 runs, 100 loops each)
%timeit df.query("A == 'foo' & A != 'bar' | A != 'baz' & A != 'buz'")
# 132 ms ± 2.43 ms per loop (mean ± std. dev. of 10 runs, 100 loops each)
%timeit df[(df.B % 5) **2 < 0.1]
# 54 ms ± 488 µs per loop (mean ± std. dev. of 10 runs, 100 loops each)
%timeit df.query("(B % 5) **2 < 0.1")
# 26.3 ms ± 320 µs per loop (mean ± std. dev. of 10 runs, 100 loops each)
3: código utilizado para producir los gráficos de rendimiento de los dos métodos para cadenas y números.
from perfplot import plot
constructor = lambda n: pd.DataFrame({'A': 'foo bar foo baz foo bar foo foo'.split()*n, 'B': np.random.rand(8*n)})
plot(
setup=constructor,
kernels=[lambda df: df[(df.B%5)**2<0.1], lambda df: df.query("(B%5)**2<0.1")],
labels= ['df[(df.B % 5) **2 < 0.1]', 'df.query("(B % 5) **2 < 0.1")'],
n_range=[2**k for k in range(4, 24)],
xlabel='Rows in DataFrame',
title='Multiple mathematical operations on numbers',
equality_check=pd.DataFrame.equals);
plot(
setup=constructor,
kernels=[lambda df: df[df.A == 'foo'], lambda df: df.query("A == 'foo'")],
labels= ["df[df.A == 'foo']", """df.query("A == 'foo'")"""],
n_range=[2**k for k in range(4, 24)],
xlabel='Rows in DataFrame',
title='Comparison operation on strings',
equality_check=pd.DataFrame.equals);
Respondido el 18 de Septiembre de 22 a las 11:09
No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas python pandas dataframe or haz tu propia pregunta.
Compruebe aquí: github.com/debaonline4u/Python_Programming/tree/master/… - debaonline4u
Esta es una comparación con SQL: pandas.pydata.org/pandas-docs/stable/comparison_with_sql.html donde puedes ejecutar pandas como SQL. - I_Al-thamary
también puede usar DFsql, para ejecutar en memoria SQL en marcos de datos de pandas medium.com/riselab/… github.com/mindsdb/dfsql - Jorge Torres
Fue conducido aquí buscando coincidencias basadas en una lista de valores de varias columnas. Esta publicación es solo sobre valores en una columna. Sugiera editar el título para que diga "valores en una columna" para evitar resultados de búsqueda falsos. - sh37211
Esta pregunta es sobre recuperando valores. Para pólipo valores, sugeriría mirar este hilo de preguntas SO y los comentarios que lo acompañan - Viet Than