Python: el valor de verdad de una serie es ambiguo. Utilice a.empty, a.bool(), a.item(), a.any() o a.all()

CorePress2024-01-25  8

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 Ucrania

28/04/2016 a las 17:54

7

Aquí tienes una solución alternativa: abs(resultado['var'])>0,25

-ColinMac

28 dic 2018 a las 17:29

7

Relacionado: Operadores lógicos para indexación booleana en Pandas

-cs95

08/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.

-AstroFloyd

3 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

MSeifert

MSeifert

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

Nipun

Nipun

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 Mortensen

2 de febrero de 2023 a las 20:43

Esta respuesta podría explicar el por qué.

-Peter Mortensen

2 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.

Respondido

28/04/2016 a las 18:15

Alejandro

Alejandro

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

Ynjxsjmh

Ynjxsjmh

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ễn

Cả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 compatible

Supongo 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 al

2 de noviembre de 2017 a las 11:13

bli

bli

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 Sami

Humza 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 Rostami

Mehdi 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 Mortensen

2 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 Kollipara

Hemanth 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

Gautam

Gautam

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 Yasirroni

Muhammad 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.

Respondido

10 de mayo de 2020 a las 21:54

iretex

iretex

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 singh

sintinder 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.

Su guía para un futuro mejor - libreflare
Su guía para un futuro mejor - libreflare