El valor de verdad de una Serie es ambiguo. Usar un.empty, un.bool(), un.item(), un.any() o un.all()
Tiene problemas para filtrar mi dataframe de resultados con una condición or
. Quiero que mi resultado df
extraiga todos los valores de la columna _var_
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 ambigua sin embargo funciona cuando divido este filtrado en dos operaciones separadas. ¿Qué está pasando aquí? no estoy seguro de dónde usar el a.empty(), a.bool(), a.item(),a.any() or a.all()
sugerido.
result = result[(result['var']>0.25) or (result['var']<-0.25)]
4 answers
Las sentencias or
y and
python requieren truth
-valores. Para pandas
estos se consideran ambiguos, por lo que debe usar "bitwise" |
(or) o &
(and) 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-sabio or
(o and
).
Solo para añadir algo más de explicación a esta declaración:{[49]]}
La excepción se lanza cuando se quiere 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 golpeaste fue un lugar donde el operador implícitamente convirtió los operandos a bool
(usaste 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 sentencias hay varias funciones de python que ocultan algunas llamadas bool
(como any
, all
, filter
, ...) estos normalmente no son problemáticos con pandas.Series
pero para completar quería mencionar estos.
En su caso, la excepción no es realmente útil, porque no menciona la alternativas correctas. Para and
y or
puede usar (si desea comparaciones basadas en elementos):
-
>>> import numpy as np >>> np.logical_or(x, y)
O simplemente el operador
|
:>>> x | y
-
>>> np.logical_and(x, y)
O simplemente el operador
&
:>>> x & y
Si está utilizando los operadores, asegúrese de establecer su paréntesis correctamente debido a la precedencia del operador.
Hay varias funciones numpy lógicas que deberían trabajar en pandas.Series
.
Las alternativas mencionadas en la Excepción son más adecuadas si las encontró al hacer if
o while
. Voy a explicar en breve 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 el
len
gth de contenedores (comolist
,tuple
, ...) como valor de verdad si no tiene booleano explícito interpretación. Así que si quieres la comprobación similar a python, puedes hacer:if x.size
oif not x.empty
en lugar deif x
. -
Si su
Series
contiene uno y solo uno valor booleano:>>> x = pd.Series([100]) >>> (x > 50).bool() True >>> (x < 50).bool() False
-
Si desea comprobar 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 comprobar si los o cualquier elemento no es cero, no-vacío o no 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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-01-01 18:50:10
Para la 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 tiene múltiples criterios, obtendrá varias columnas devueltas. Esta es la razón por la lógica de la unión es ambigua. Usando and
o or
trata cada columna por separado, por lo que primero debe reducir esa columna a un solo valor booleano. Por ejemplo, para ver si cualquier 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 comprimir 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 más detalles, consulte Indexación booleana en los documentos.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-04-28 18:23:59
O, alternativamente, puede usar el módulo de operador. Más información detallada está aquí Python docs
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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-01-19 07:48:25
Esta excelente respuesta explica muy bien lo que está sucediendo y proporciona una solución. Me gustaría añadir otra solución que podría ser adecuada en casos similares: el uso de la query
método:
result = result.query("(var > 0.25) or (var < -0.25)")
Véase también http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-query .
(Algunas pruebas con un dataframe con el que estoy trabajando actualmente sugieren que este método es un poco más lento que usar los operadores bitwise en series de booleanos: 2 ms vs 870 µs)
Una advertencia: Al menos una situación en la que esto no es sencillo es cuando los nombres de las columnas son expresiones de python. Tenía columnas nombradas 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 estaba tratando de hacer algo a partir de los dos primeros columnas en lugar de identificar la expresión con el nombre de la tercera columna.
Se propone una posible solución aquí.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-11-02 12:20:55