Estoy trabajando con el índice booleano en Pandas. La pregunta es por qué la declaración:
a[(a['some_column']==some_number) & (a['some_other_column']==some_other_number)]
funciona bien mientras
a[(a['some_column']==some_number) and (a['some_other_column']==some_other_number)]
sale con error?
Ejemplo:
a=pd.DataFrame({'x':[1,1],'y':[10,20]})
In: a[(a['x']==1)&(a['y']==10)]
Out: x y
0 1 10
In: a[(a['x']==1) and (a['y']==10)]
Out: ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
and != &
. Eland
operador en Python no se puede anular, mientras que el&
operador (__and__
) sí. De ahí la elección del uso&
en numpy y pandas.Respuestas:
Cuando tu dices
Está pidiendo implícitamente a Python que convierta
(a['x']==1)
y(a['y']==10)
a valores booleanos.Las matrices NumPy (de longitud mayor que 1) y los objetos Pandas como Series no tienen un valor booleano; en otras palabras, aumentan
cuando se usa como un valor booleano. Eso es porque no está claro cuándo debería ser Verdadero o Falso . Algunos usuarios pueden asumir que son Verdaderos si tienen una longitud distinta de cero, como una lista de Python. Otros pueden desear que sea Verdadero solo si todos sus elementos son Verdaderos. Otros pueden querer que sea Verdadero si alguno de sus elementos es Verdadero.
Debido a que hay tantas expectativas en conflicto, los diseñadores de NumPy y Pandas se niegan a adivinar, y en su lugar plantean un ValueError.
En su lugar, debe ser explícita, llamando al
empty()
,all()
oany()
método para indicar el comportamiento deseado.En este caso, sin embargo, parece que no desea una evaluación booleana, desea elementos lógicos y. Eso es lo
&
que realiza el operador binario:devuelve una matriz booleana.
Por cierto, como señala alexpmil , los paréntesis son obligatorios ya que
&
tiene una precedencia de operador más alta que==
. Sin los paréntesis,a['x']==1 & a['y']==10
se evaluaría comoa['x'] == (1 & a['y']) == 10
lo que a su vez sería equivalente a la comparación encadenada(a['x'] == (1 & a['y'])) and ((1 & a['y']) == 10)
. Esa es una expresión de la formaSeries and Series
. El uso deand
dos series volvería a desencadenar lo mismoValueError
que anteriormente. Por eso los paréntesis son obligatorios.fuente
x and y
active la evaluación debool(x)
ybool(y)
. Python "primero evalúax
; six
es falso, se devuelve su valor; de lo contrario,y
se evalúa y se devuelve el valor resultante". Por lo que la sintaxisx and y
no se puede utilizar para el elemento lógico-wised, y puesto que solamentex
oy
pueden ser devueltos. Por el contrario, losx & y
desencadenantesx.__and__(y)
y el__and__
método pueden definirse para devolver lo que queramos.==
cláusula son obligatorios .a['x']==1 & a['y']==10
devuelve el mismo error que en la pregunta.TLDR; Los operadores lógicos en Pandas son
&
,|
y~
, ¡y los paréntesis(...)
son importantes!Python es
and
,or
ynot
operadores lógicos están diseñados para trabajar con escalares. Así que Pandas tuvo que hacerlo mejor y anular los operadores bit a bit para lograr la versión vectorizada (por elementos) de esta funcionalidad.Entonces, lo siguiente en python (
exp1
yexp2
son expresiones que evalúan un resultado booleano) ...... se traducirá a ...
para pandas
Si en el proceso de realizar una operación lógica obtiene un
ValueError
, entonces necesita usar paréntesis para agrupar:Por ejemplo,
Y así.
Indexación booleana : Una operación común es calcular máscaras booleanas a través de condiciones lógicas para filtrar los datos. Pandas proporciona tres operadores:
&
para AND lógico,|
para OR lógico y~
para NOT lógico.Considere la siguiente configuración:
Lógico Y
Para lo
df
anterior, digamos que desea devolver todas las filas donde A <5 y B> 5. Esto se hace calculando máscaras para cada condición por separado, y ANDing.&
Operador Bitwise sobrecargadoAntes de continuar, tome nota de este extracto particular de los documentos, que establece
Entonces, con esto en mente, el elemento lógico AND se puede implementar con el operador bit a bit
&
:Y el siguiente paso de filtrado es simplemente,
Los paréntesis se utilizan para anular el orden de precedencia predeterminado de los operadores bit a bit, que tienen mayor precedencia sobre los operadores condicionales
<
y>
. Consulte la sección de Precedencia del operador en los documentos de Python.Si no usa paréntesis, la expresión se evalúa incorrectamente. Por ejemplo, si intenta accidentalmente algo como
Se analiza como
Que se convierte
Que se convierte (ver los documentos de Python en la comparación de operadores encadenados ),
Que se convierte
Que tira
Entonces, ¡no cometas ese error! 1
Evitar la agrupación de paréntesis
La solución es en realidad bastante simple. La mayoría de los operadores tienen un método enlazado correspondiente para DataFrames. Si las máscaras individuales se crean utilizando funciones en lugar de operadores condicionales, ya no necesitará agrupar por parens para especificar el orden de evaluación:
Consulte la sección sobre Comparaciones flexibles. . Para resumir, tenemos
Otra opción para evitar paréntesis es usar
DataFrame.query
(oeval
):He documentado extensamente
query
yeval
en evaluación de expresión dinámica en pandas usando pd.eval () .operator.and_
Le permite realizar esta operación de manera funcional. Llama internamente lo
Series.__and__
que corresponde al operador bit a bit.Por lo general, no necesitará esto, pero es útil saberlo.
Generalizando:
np.logical_and
(ylogical_and.reduce
)Otra alternativa es usar
np.logical_and
, que tampoco necesita agrupación de paréntesis:np.logical_and
es un ufunc (funciones universales) , y la mayoría de los ufuncs tienen unreduce
método. Esto significa que es más fácil generalizarlogical_and
si tiene varias máscaras para AND. Por ejemplo, para y máscarasm1
ym2
ym3
con&
, usted tendría que hacerSin embargo, una opción más fácil es
Esto es poderoso, porque le permite construir sobre esto con una lógica más compleja (por ejemplo, generar dinámicamente máscaras en una comprensión de lista y agregarlas todas):
1 - Sé que estoy insistiendo en este punto, pero por favor tengan paciencia conmigo. Este es un error de principiante muy , muy común, y debe explicarse muy a fondo.
O lógico
Para lo
df
anterior, digamos que desea devolver todas las filas donde A == 3 o B == 7.Bitwise sobrecargado
|
Si aún no lo ha hecho, lea también la sección sobre Lógico Y arriba, todas las advertencias se aplican aquí.
Alternativamente, esta operación se puede especificar con
operator.or_
Llamadas
Series.__or__
bajo el capó.np.logical_or
Para dos condiciones, use
logical_or
:Para máscaras múltiples, use
logical_or.reduce
:NO lógico
Dada una máscara, como
Si necesita invertir cada valor booleano (para que el resultado final sea
[False, False, True]
), puede usar cualquiera de los métodos a continuación.Bitwise
~
Una vez más, las expresiones deben estar entre paréntesis.
Esto internamente llama
Pero no lo use directamente.
operator.inv
Internamente llama
__invert__
a la serie.np.logical_not
Esta es la variante numpy.
Nota,
np.logical_and
puede ser sustituido pornp.bitwise_and
,logical_or
conbitwise_or
ylogical_not
coninvert
.fuente
|
, que es equivalente anumpy.bitwise_or
, en lugar denumpy.logical_or
. ¿Puedo preguntar por qué? ¿No estánumpy.logical_or
diseñado específicamente para esta tarea? ¿Por qué agregar la carga de hacerlo a nivel de bits para cada par de elementos?|
para operaciones booleanas basadas en elementos. Pero para mí, esa documentación es más un "tutorial", y en contraste, siento que estas referencias de API están más cerca de la fuente de la verdad: numpy.bitwise_or y numpy.logical_or , así que estoy tratando de entender qué es descrito aquí.Es importante darse cuenta de que no se puede utilizar cualquiera de los Python operadores lógicos (
and
,or
onot
) enpandas.Series
opandas.DataFrame
s (de manera similar no se puede utilizar ennumpy.array
s con más de un elemento). La razón por la que no puede usarlos es porque invocan implícitamentebool
sus operandos que arrojan una Excepción porque estas estructuras de datos decidieron que el valor booleano de una matriz es ambiguo:Cubrí esto más extensamente en mi respuesta al "El valor de verdad de una Serie es ambiguo. Use a.empty, a.bool (), a.item (), a.any () o a.all ()" Q + A .
Funciones lógicas de NumPys
Sin embargo NumPy proporciona elemento a elemento equivalentes operativo para estos operadores como las funciones que se pueden utilizar en
numpy.array
,pandas.Series
,pandas.DataFrame
, o cualquier otra (conforme)numpy.array
subclase:and
tienenp.logical_and
or
tienenp.logical_or
not
tienenp.logical_not
numpy.logical_xor
que no tiene equivalente en Python pero es una operación lógica "exclusiva o"Entonces, esencialmente, uno debe usar (suponiendo
df1
ydf2
son pandas DataFrames):Funciones bit a bit y operadores bit a bit para booleanos
Sin embargo, en caso de que tenga una matriz booleana NumPy, series pandas o marcos de datos pandas, también podría usar las funciones bit a nivel de elemento (para los booleanos son, o al menos deberían ser) indistinguibles de las funciones lógicas:
np.bitwise_and
o el&
operadornp.bitwise_or
o el|
operadornp.invert
(o el aliasnp.bitwise_not
) o el~
operadornp.bitwise_xor
o el^
operadorPor lo general, se utilizan los operadores. Sin embargo, cuando se combina con operadores de comparación, uno debe recordar ajustar la comparación entre paréntesis porque los operadores bit a bit tienen una precedencia más alta que los operadores de comparación :
Esto puede ser irritante porque los operadores lógicos de Python tienen una precedencia más baja que los operadores de comparación, por lo que normalmente escribe
a < 10 and b > 10
(dóndea
yb
son, por ejemplo, enteros simples) y no necesita el paréntesis.Diferencias entre operaciones lógicas y bit a bit (en no booleanos)
Es realmente importante enfatizar que las operaciones bit y lógicas solo son equivalentes para matrices booleanas NumPy (y series booleanas y marcos de datos). Si estos no contienen booleanos, las operaciones darán resultados diferentes. Incluiré ejemplos usando matrices NumPy pero los resultados serán similares para las estructuras de datos de pandas:
Y dado que NumPy (y de manera similar pandas) hace cosas diferentes para los índices booleanos ( matrices de índices booleanos o "enmascarados" ) y enteros ( matrices de índices), los resultados de la indexación también serán diferentes:
Tabla de resumen
Donde el operador lógico no funciona para matrices NumPy , series pandas y marcos de datos pandas. Los otros trabajan en estas estructuras de datos (y objetos Python simples) y trabajan en función de los elementos. Sin embargo, tenga cuidado con la inversión bit a bit en Python simple
bool
porque el bool se interpretará como enteros en este contexto (por ejemplo,~False
retornos-1
y~True
retornos-2
).fuente