Quiero filtrar mi marco de datos con una condición o para mantener las filas con valores de una columna en particular que están fuera del rango [-0,25, 0,25]. Lo intenté:
df = df[(df['col'] < -0.25) or (df['col'] > 0.25)]
Pero me sale el error:
ValueError: el valor de verdad de una serie es ambiguo. Utilice a.empty, a.bool(), a.item(), a.any() o a.all().
127
uso | en lugar de o
– MaxU - apoye a Ucrania28/04/2016 a las 17:54
7
Aquí tienes una solución alternativa: abs(resultado['var'])>0,25
-ColinMac28 dic 2018 a las 17:29
7
Relacionado: Operadores lógicos para indexación booleana en Pandas
-cs9508/03/2019 a las 22:09
4
Me encontré con el mismo mensaje de error usando la función estándar max(). Reemplazarlo con numpy.maximum() para máximos de elementos entre dos valores resolvió mi problema.
-AstroFloyd3 de febrero de 2021 a las 11:34
Las declaraciones or y Python requieren valores de verdad. En el caso de los pandas, estos se consideran ambiguos, por lo que se deben utilizar métodos "bit a bit". | (o) o & (y) operaciones:
df = df[(df['col'] < -0.25) | (df['col'] > 0.25)]
Estos están sobrecargados para este tipo de estructuras de datos para producir elementos o o y.
Solo para agregar una explicación más a esta afirmación:
La excepción se lanza cuando yQuieres obtener el bool de pandas.Series:
>>> import pandas as pd
>>> x = pd.Series([1])
>>> bool(x)
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
Llegaste a un lugar donde el operador convirtió implícitamente los operandos a bool (usaste o pero también sucede para y, si y mientras):
>>> x or x
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
>>> x and x
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
>>> if x:
... print('fun')
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
>>> while x:
... print('fun')
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
Además de estas cuatro declaraciones, hay varias funciones de Python que ocultan algunas llamadas bool (como cualquiera, todo, filtro, ...). Normalmente no son problemáticos con pandas.Series, pero para completar quería mencionarlos.
En su caso, la excepción no es realmente útil porque no menciona las alternativas correctas. Para y y o, si desea realizar comparaciones entre elementos, puede utilizar:
numpy.logic_or:
>>> import numpy as np
>>> np.logical_or(x, y)
o simplemente el | operador:
>>> x | y
numpy.logic_and:
>>> np.logical_and(x, y)
o simplemente el & operador:
>>> x & y
Si estás usando el operadorrs, asegúrese de configurar los paréntesis correctamente debido a la precedencia de los operadores.
Hay varias funciones lógicas de NumPy que deberían funcionar en pandas.Series.
Las alternativas mencionadas en la excepción son más adecuadas si las encontró al hacer if o while. En breve explicaré cada uno de estos:
Si quieres comprobar si tu Serie está vacía:
>>> x = pd.Series([])
>>> x.empty
True
>>> x = pd.Series([1])
>>> x.empty
False
Python normalmente interpreta la longitud de los contenedores (como lista, tupla, ...) como valor de verdad si no tiene una interpretación booleana explícita. Entonces, si desea realizar una verificación similar a la de Python, puede hacer: if x.size o if not x.empty en lugar de if x.
Si su serie contiene un solo valor booleano:
>>> x = pd.Series([100])
>>> (x > 50).bool()
True
>>> (x < 50).bool()
False
Si desea verificar el primer y único elemento de su serie (como .bool(), pero funciona incluso sinContenidos n-booleanos):
>>> x = pd.Series([100])
>>> x.item()
100
Si desea comprobar si todos o alguno de los elementos no son cero, no están vacíos o no son falsos:
>>> x = pd.Series([0, 1, 2])
>>> x.all() # Because one element is zero
False
>>> x.any() # because one (or more) elements are non-zero
True
Respondido al 28 de abril de 2016 a las 17:54
MSeifertMSeifert
148k
38
38 insignias de oro
336
336 insignias de plata
356
356 insignias de bronce
0
Pandas utiliza bit a bit & |. Además, cada condición debe estar envuelta dentro ( ).
Esto funciona:
data_query = data[(data['year'] >= 2005) & (data['year'] <= 2010)]
Pero la misma consulta sin paréntesis no:
data_query = data[(data['year'] >= 2005 & data['year'] <= 2010)]
Respondido 11 de septiembre de 2019 a las 22:36
NipunNipun
1.319
1
1 insignia de oro
7
7 insignias de plata
3
3 insignias de bronce
2
¿Por qué cada condición debería incluirse dentro de ( )? Por favor responde by editar (cambiar) su respuesta, no aquí en los comentarios (sin "Editar:", "Actualizar:" o similar; la respuesta debería aparecer como si estuviera escrita hoy). (Pero ****** sin ****** "Editar:", "Actualizar:" o similar; la respuesta debería aparecer como si estuviera escrita hoy)
-Peter Mortensen2 de febrero de 2023 a las 20:43
Esta respuesta podría explicar el por qué.
-Peter Mortensen2 de febrero de 2023 a las 20:54
Para lógica booleana, utilice & y |.
np.random.seed(0)
df = pd.DataFrame(np.random.randn(5,3), columns=list('ABC'))
>>> df
A B C
0 1.764052 0.400157 0.978738
1 2.240893 1.867558 -0.977278
2 0.950088 -0.151357 -0.103219
3 0.410599 0.144044 1.454274
4 0.761038 0.121675 0.443863
>>> df.loc[(df.C > 0.25) | (df.C < -0.25)]
A B C
0 1.764052 0.400157 0.978738
1 2.240893 1.867558 -0.977278
3 0.410599 0.144044 1.454274
4 0.761038 0.121675 0.443863
Para ver qué está sucediendo, obtienes una columna de valores booleanos para cada comparación, por ejemplo,
df.C > 0.25
0 True
1 False
2 False
3 True
4 True
Name: C, dtype: bool
Cuando tenga varios criterios, obtendrá varias columnas. Por eso la lógica de unión es ambigua. El uso de and or or trata cada columna por separado, por lo que primero debe reducir esa columna a un único valor booleano. Por ejemplo, para ver si algún valor o todos los valores en cada una de las columnas es Verdadero.
# Any value in either column is True?
(df.C > 0.25).any() or (df.C < -0.25).any()
True
# All values in either column is True?
(df.C > 0.25).all() or (df.C < -0.25).all()
False
Una forma complicada de lograr lo mismo es comprimir todas estas columnas y realizar la lógica adecuada.
>>> df[[any([a, b]) for a, b in zip(df.C > 0.25, df.C < -0.25)]]
A B C
0 1.764052 0.400157 0.978738
1 2.240893 1.867558 -0.977278
3 0.410599 0.144044 1.454274
4 0.761038 0.121675 0.443863
Para obtener más detalles, consulte Indexación booleana en la documentación.
Respondido28/04/2016 a las 18:15
AlejandroAlejandro
107k
32
32 insignias de oro
205
205 insignias de plata
198
198 insignias de bronce
Esta es una pregunta bastante común para los principiantes cuando crean múltiples condiciones en Pandas. En términos generales, hay dos condiciones posibles que causan este error:
Condición 1: Operador Python Precedencia
Hay un párrafo de indexación booleana | Indexación y selección de datos: la documentación de pandas explica esto:
Otra operación común es el uso de vectores booleanos para filtrar los datos. Los operadores son: | para o, & para y, y ~ para no. Estos deben agruparse mediante paréntesis.
Por defecto, Python evaluará una expresión como df['A'] > 2 y 2 df['B'] < 3 como df['A'] > (2 y df['B']) < 3, mientras que el orden de evaluación deseado es (df['A'] > 2) & (df['B'] < 3).
# Wrong
df['col'] < -0.25 | df['col'] > 0.25
# Right
(df['col'] < -0.25) | (df['col'] > 0.25)
Existen algunas formas posibles de eliminar los paréntesis y las abordaré más adelante.
Condición 2: Operador/Declaración Inapropiados
Como se explica en la cita anterior, es necesario utilizar | para o, & para y, y ~ para no.
# Wrong
(df['col'] < -0.25) or (df['col'] > 0.25)
# Right
(df['col'] < -0.25) | (df['col'] > 0.25)
Otra situación posible es que esté utilizando una serie booleana en una declaración if.
# Wrong
if pd.Series([True, False]):
pass
Está claro que la declaración if de Python acepta expresiones de tipo booleano en lugar de la serie Pandas. Debe utilizar pandas.Series.any o los métodos enumerados en el mensaje de error para convertir la serie a un valor que se ajuste a sus necesidades.
Por ejemplo:
# Right
if df['col'].eq(0).all():
# If you want all column values equal to zero
print('do something')
# Right
if df['col'].eq(0).any():
# If you want at least one column value equal to zero
print('do something')
Hablemos de formas de escapar de los paréntesis en la primera situación.
Usa las funciones matemáticas de Pandas
Pandas ha definido muchas funciones matemáticas, incluida la comparación, de la siguiente manera:
pandas.Series.lt() por menos de; pandas.Series.gt() para mayor que; pandas.Series.le() por menos e igual; pandas.Series.ge() para mayor e igual; pandas.Series.ne() para no igual; pandas.Series.eq() para igual;Como resultado, puedes usar
df = df[(df['col'] < -0.25) | (df['col'] > 0.25)]
# is equal to
df = df[df['col'].lt(-0.25) | df['col'].gt(0.25)]
Utilizar pandas.Series.between()
Si desea seleccionar filas entre dos valores, puede usar pandas.Series.between:
df['col].between(izquierda, derecha) es igual a (izquierda <= df['col']) & (df['col'] <= derecha); df['col].between(left, right, inclusive='left) es igual a (izquierda <= df['col']) & (df['col'] < derecha); df['col].between(left, right, inclusive='right') es igual a (izquierda < df['col']) & (df['col'] <= derecha); df['col].between(left, right, inclusive='neither') es igual a (izquierda < df['col']) & (df['col'] < derecha);df = df[(df['col'] > -0.25) & (df['col'] < 0.25)]
# is equal to
df = df[df['col'].between(-0.25, 0.25, inclusive='neither')]
Usa pandas.DataFrame.query()
El documento al que se hace referencia anteriormente tiene un capítulo. El método query() explica esto bien.
pandas.DataFrame.query() puede ayudarle a seleccionar un DataFramecon una cadena de condición. Dentro de la cadena de consulta, puede utilizar operadores bit a bit (& y |) y sus primos booleanos (y y o). Además, puedes omitir los paréntesis, pero no lo recomiendo por motivos de legibilidad.
df = df[(df['col'] < -0.25) | (df['col'] > 0.25)]
# is equal to
df = df.query('col < -0.25 or col > 0.25')
Usa pandas.DataFrame.eval()
pandas.DataFrame.eval() evalúa una cadena que describe operaciones en columnas de DataFrame. Por lo tanto, podemos utilizar este método para construir nuestras múltiples condiciones. La sintaxis es la misma con pandas.DataFrame.query().
df = df[(df['col'] < -0.25) | (df['col'] > 0.25)]
# is equal to
df = df[df.eval('col < -0.25 or col > 0.25')]
pandas.DataFrame.query() y pandas.DataFrame.eval() pueden hacer más cosas de las que describo aquí. Se recomienda leer su documentación y divertirse con ellos.
respondió21 de abril de 2022 a las 14:26
YnjxsjmhYnjxsjmh
28,9k
7
7 insignias de oro
36
36 insignias de plata
54
54 de bronce insignias
O, alternativamente, puede utilizar el módulo de operador. Hay información más detallada en la documentación de Python:
import operator
import numpy as np
import pandas as pd
np.random.seed(0)
df = pd.DataFrame(np.random.randn(5,3), columns=list('ABC'))
df.loc[operator.or_(df.C > 0.25, df.C < -0.25)]
A B C
0 1.764052 0.400157 0.978738
1 2.240893 1.867558 -0.977278
3 0.410599 0.144044 1.454274
4 0.761038 0.121675 0.4438
Respondido 19 de enero de 2017 a las 7:48
Cảnh aàn NguyễnCảnh Toàn Nguyễn
480
6
6 insignias de plata
12
12 insignias de bronce
1
El operador me ayudó con un problema en jinja. Jinja no acepta & operador... La consulta de Pandas no puede alcanzar la variable jinja. ¡Pero .loc con operador funciona! ¡Gracias!
- Dmitri K.13 de febrero de 2023 a las 9:11
Esta excelente respuesta explica muy bien lo que está pasando y proporciona una solución. Me gustaría agregar otra solución que podría ser adecuada en casos similares: usar el método de consulta:
df = df.query("(col > 0.25) or (col < -0.25)")
Consulte también Indexación y selección de datos.
(Algunas pruebas con un marco de datos con el que estoy trabajando actualmente sugieren que este método es un poco más lento que usar operadores bit a bit en series de booleanos: 2 ms frente a 870 μs)
Una advertencia: al menos una situación en la que esto no es sencillo es cuando los nombres de las columnas resultan ser expresiones de Python. Tenía columnas denominadas WT_38hph_IP_2, WT_38hph_input_2 y log2(WT_38hph_IP_2/WT_38hph_input_2) y quería realizar la siguiente consulta: "(log2(WT_38hph_IP_2/WT_38hph_input_2) > 1) and (WT_38hph_IP_2 > 20)"
Obtuve elsiguiente cascada de excepciones:
Error clave: 'log2' UndefinedVariableError: el nombre 'log2' no está definido Error de valor: "log2" no es una función compatibleSupongo que esto sucedió porque el analizador de consultas intentaba crear algo a partir de las dos primeras columnas en lugar de identificar la expresión con el nombre de la tercera columna.
Aquí se propone una posible solución.
Respondido al2 de noviembre de 2017 a las 11:13
blibli
7,789
8
8 insignias de oro
50
50 insignias de plata
96
96 insignias de bronce
Si tienes más de un valor:
df['col'].all()
Si es un solo valor:
df['col'].item()
Respondido 20 de septiembre de 2021 a las 15:18
Humza SamiHumza Sami
118
1
1 insignia de plata
7
7 insignias de bronce
Yorecibía un error en este comando:
if df != '':
pass
Pero funcionó cuando lo cambié a esto:
if df is not '':
pass
respondido el 5 de julio de 2021 a las 15:38
Mehdi RostamiMehdi Rostami
139
2
2 insignias de plata
5
5 insignias de bronce
1
Eso es interesante, pero podría ser incidental. ¿Cuál es la explicación?
-Peter Mortensen2 de febrero de 2023 a las 20:51
Necesitas usar operadores bit a bit | en lugar de o y & en lugar de y en pandas. No puedes simplemente usar las declaraciones bool de Python.
Para un filtrado mucho más complejo, cree una máscara y aplíquela en el marco de datos. Pon toda tu consulta en la mascarilla y aplícala. Supongamos,
mask = (df["col1"]>=df["col2"]) & (stock["col1"]<=df["col2"])
df_new = df[mask]
Respondido al 16 de julio de 2020 a las 7:39
Hemanth KolliparaHemanth Kollipara
932
12
12 insignias de plata
16
16 insignias de bronce
Me he enfrentado al mismo problema mientras trabajaba en el marco de datos de Panda.
He usado: numpy.logic_and:
Aquí estoy intentando seleccionar la fila con el Id. que coincide con 41d7853 y el grado_tipo no con la Certificación.
Como a continuación:
display(df_degrees.loc[np.logical_and(df_degrees['person_id'] == '41d7853' , df_degrees['degree_type'] !='Certification')])
Si intento escribir código como el siguiente:
display(df_degrees.loc[df_degrees['person_id'] == '41d7853' and df_degrees['degree_type'] !='Certification'])
Recibiremos el error:
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
He usado numpy.logic_y funcionó para mí.
respondió17 de octubre de 2022 a las 2:13
GautamGautam
3.807
5
5 insignias de oro
38
38 insignias de plata
59
59 insignias de bronce
Intentaré dar un punto de referencia de las tres formas más comunes (también mencionadas anteriormente):
from timeit import repeat
setup = """
import numpy as np;
import random;
x = np.linspace(0,100);
lb, ub = np.sort([random.random() * 100, random.random() * 100]).tolist()
"""
stmts = 'x[(x > lb) * (x <= ub)]', 'x[(x > lb) & (x <= ub)]', 'x[np.logical_and(x > lb, x <= ub)]'
for _ in range(3):
for stmt in stmts:
t = min(repeat(stmt, setup, number=100_000))
print('%.4f' % t, stmt)
print()
Resultado:
0.4808 x[(x > lb) * (x <= ub)]
0.4726 x[(x > lb) & (x <= ub)]
0.4904 x[np.logical_and(x > lb, x <= ub)]
0.4725 x[(x > lb) * (x <= ub)]
0.4806 x[(x > lb) & (x <= ub)]
0.5002 x[np.logical_and(x > lb, x <= ub)]
0.4781 x[(x > lb) * (x <= ub)]
0.4336 x[(x > lb) & (x <= ub)]
0.4974 x[np.logical_and(x > lb, x <= ub)]
Pero * no es compatible con Panda Series, y NumPy Array es más rápido que el marco de datos de pandas (alrededor de 1000 veces más lento, ver número):
from timeit import repeat
setup = """
import numpy as np;
import random;
import pandas as pd;
x = pd.DataFrame(np.linspace(0,100));
lb, ub = np.sort([random.random() * 100, random.random() * 100]).tolist()
"""
stmts = 'x[(x > lb) & (x <= ub)]', 'x[np.logical_and(x > lb, x <= ub)]'
for _ in range(3):
for stmt in stmts:
t = min(repeat(stmt, setup, number=100))
print('%.4f' % t, stmt)
print()
Resultado:
0.1964 x[(x > lb) & (x <= ub)]
0.1992 x[np.logical_and(x > lb, x <= ub)]
0.2018 x[(x > lb) & (x <= ub)]
0.1838 x[np.logical_and(x > lb, x <= ub)]
0.1871 x[(x > lb) & (x <= ub)]
0.1883 x[np.logical_and(x > lb, x <= ub)]
Nota: agregar una línea de código x = x.to_numpy() necesitaráunos 20 µs.
Para aquellos que prefieren %timeit:
import numpy as np
import random
lb, ub = np.sort([random.random() * 100, random.random() * 100]).tolist()
lb, ub
x = pd.DataFrame(np.linspace(0,100))
def asterik(x):
x = x.to_numpy()
return x[(x > lb) * (x <= ub)]
def and_symbol(x):
x = x.to_numpy()
return x[(x > lb) & (x <= ub)]
def numpy_logical(x):
x = x.to_numpy()
return x[np.logical_and(x > lb, x <= ub)]
for i in range(3):
%timeit asterik(x)
%timeit and_symbol(x)
%timeit numpy_logical(x)
print('\n')
Resultado:
23 µs ± 3.62 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
35.6 µs ± 9.53 µs per loop (mean ± std. dev. of 7 runs, 100000 loops each)
31.3 µs ± 8.9 µs per loop (mean ± std. dev. of 7 runs, 100000 loops each)
21.4 µs ± 3.35 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
21.9 µs ± 1.02 µs per loop (mean ± std. dev. of 7 runs, 100000 loops each)
21.7 µs ± 500 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
25.1 µs ± 3.71 µs per loop (mean ± std. dev. of 7 runs, 100000 loops each)
36.8 µs ± 18.3 µs per loop (mean ± std. dev. of 7 runs, 100000 loops each)
28.2 µs ± 5.97 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
respondido 23 de octubre de 2020 a las 16:49
Muhammad YasirroniMuhammad Yasirroni
1.742
14
14 insignias de plata
22
22 insignias de bronce
Encontré el mismo error y me quedé estancado con un marco de datos de PySpark durante unos días. Pude resolverlo exitosamente completando los valores de na con 0ya que estaba comparando valores enteros de dos campos.
Respondido10 de mayo de 2020 a las 21:54
iretexiretex
61
10
10 insignias de bronce
Una cosa menor que me hizo perder el tiempo.
Coloque las condiciones (si se compara usando " = ", " != ") entre paréntesis. No hacerlo también genera esta excepción.
Esto funcionará:
df[(some condition) conditional operator (some conditions)]
Esto no:
df[some condition conditional-operator some condition]
Respondido al 9 de octubre de 2020 a las 9:37
satinder singhsintinder satin
180
15
15 insignias de bronce
En mi caso, estaba teniendo un error de valor de tipo debido al cual se generaba este error. Asegúrese de que al operador de comparación se le haya asignado el mismo elemento de tipo de datos para comparar.