El valor de la verdad de una serie es ambiguo.Usa a.empty,a.bool(),a.item(),a.any()o a.all()

python pandas dataframe boolean filtering


Tener problemas para filtrar el marco de datos de resultados con una condición or . Quiero que mi resultado df extraiga todos los valores var de la columna que estén por encima de 0.25 y por debajo de -0.25.

Esta lógica a continuación me da un valor de verdad ambiguo, sin embargo, funciona cuando divido este filtrado en dos operaciones separadas. ¿Que está sucediendo aquí? no estoy seguro de dónde usar el sugerido a.empty(), a.bool(), a.item(),a.any() or a.all() .

 result = result[(result['var']>0.25) or (result['var']<-0.25)]



Answer 1 MSeifert


El or e and declaraciones pitón requieren truth -valores. Para los pandas , estos se consideran ambiguos, por lo que debe usar "bit a bit" | (o) o & (y) operaciones:

result = result[(result['var']>0.25) | (result['var']<-0.25)]

Estos están sobrecargados para este tipo de estructuras de datos para producir el elemento inteligente or (o and ).


Sólo para añadir algo más de explicación a esta declaración:

La excepción se produce cuando desea obtener el bool de un 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().

Lo que golpeó fue un lugar donde el operador convirtió implícitamente los operandos a bool (usó or pero también sucede para and , if y while ):

>>> 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 4 declaraciones, hay varias funciones de python que ocultan algunas llamadas bool (como any , all , filter , ...) normalmente no son problemáticas con pandas.Series , pero para completar, quería mencionarlas.


En su caso, la excepción no es realmente útil, porque no menciona las alternativas correctas . Para and y or puedes usar (si quieres comparaciones basadas en elementos):

  • numpy.logical_or:

    >>> import numpy as np
    >>> np.logical_or(x, y)

    o simplemente el | operador:

    >>> x | y
  • numpy.logical_and:

    >>> np.logical_and(x, y)

    o simplemente el operador & :

    >>> x & y

Si está utilizando los operadores, asegúrese de configurar sus paréntesis correctamente debido a la precedencia del operador .

Hay varias funciones lógicas numpy que deberían funcionar en pandas.Series .


Las alternativas mencionadas en la Excepción son más adecuadas si la encontró al hacer if o while . En breve explicaré cada uno de estos:

  • Si desea verificar si su Serie está vacía :

    >>> x = pd.Series([])
    >>> x.empty
    True
    >>> x = pd.Series([1])
    >>> x.empty
    False

    Python normalmente interpreta la len GTH de contenedores (como list , tuple , ...) como valor de verdad si no tiene una interpretación explícita booleano. Entonces, si desea la comprobación similar a Python, puede hacer: if x.size o if not x.empty lugar de if x .

  • Si su Series contiene uno y solo un 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 para contenidos no booleanos):

    >>> x = pd.Series([100])
    >>> x.item()
    100
  • Si desea verificar si todo o algún artículo no es cero, no está vacío o no es falso:

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



Answer 2 Alexander


Para lógica booleana, use & 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 lo que está sucediendo,se obtiene una columna de 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 devueltas. Es por eso que la lógica de unión es ambigua. Usando and / or trata cada columna por separado, por lo que primero debe reducir esa columna a un solo 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 enrevesada de lograr lo mismo es cerrar todas estas columnas juntas,y realizar la lógica apropiada.

>>> 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 Indización booleana en los documentos.




Answer 3 Nipun


Los pandas usan bitwise '&' '|' y cada condición debe estar envuelta en un '()'

Por ejemplo,las siguientes obras

data_query = data[(data['year'] >= 2005) & (data['year'] <= 2010)]

Pero la misma consulta sin los corchetes adecuados no

data_query = data[(data['year'] >= 2005 & data['year'] <= 2010)]



Answer 4 Cảnh Toàn Nguyễn


O, alternativamente, puede usar el módulo Operador. Información más detallada está aquí Documentos 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



Answer 5 bli


Esta excelente respuesta explica muy bien lo que está sucediendo y brinda una solución. Me gustaría agregar otra solución que podría ser adecuada en casos similares: utilizando el método de query :

result = result.query("(var > 0.25) or (var < -0.25)")

Ver también http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-query .

(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 los 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 columna son 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 la siguiente cascada de excepciones:

  • KeyError: 'log2'
  • UndefinedVariableError: name 'log2' is not defined
  • ValueError: "log2" is not a supported function

Supongo que esto sucedió porque el analizador de consultas intentaba hacer algo con 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 alternativa .