python - iloc - El valor de verdad de una serie es ambiguo. Utilice a.empty, a.bool(), a.item(), a.any() o a.all()
pandas select rows by condition (5)
Las declaraciones
or
y python requieren valores de
truth
.
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
).
Solo para agregar más explicaciones 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):
-
>>> 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 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 longitud de los contenedores (como
list
,tuple
, ...) como valor de verdad si no tiene una interpretación booleana explícita. Entonces, si desea la comprobación similar a Python, puede hacer:if x.size
oif not x.empty
lugar deif 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 elemento 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
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
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)]
Los pandas usan bitwise ''&'' ''|'' y cada condición debe estar envuelta en un ''()''
Por ejemplo, siguientes trabajos
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)]
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
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, obtienes una columna de booleanos para cada comparación, por ej.
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 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 Indización booleana en los documentos.
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 estaba tratando de hacer algo de las dos primeras columnas en lugar de identificar la expresión con el nombre de la tercera columna.
here se propone una posible solución alternativa.