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 != &. Elandoperador 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']==10se evaluaría comoa['x'] == (1 & a['y']) == 10lo 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 deanddos series volvería a desencadenar lo mismoValueErrorque anteriormente. Por eso los paréntesis son obligatorios.fuente
x and yactive la evaluación debool(x)ybool(y). Python "primero evalúax; sixes falso, se devuelve su valor; de lo contrario,yse evalúa y se devuelve el valor resultante". Por lo que la sintaxisx and yno se puede utilizar para el elemento lógico-wised, y puesto que solamentexoypueden ser devueltos. Por el contrario, losx & ydesencadenantesx.__and__(y)y el__and__método pueden definirse para devolver lo que queramos.==cláusula son obligatorios .a['x']==1 & a['y']==10devuelve 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,orynotoperadores 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 (
exp1yexp2son 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:
¶ AND lógico,|para OR lógico y~para NOT lógico.Considere la siguiente configuración:
Lógico Y
Para lo
dfanterior, 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
queryyevalen 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_andes un ufunc (funciones universales) , y la mayoría de los ufuncs tienen unreducemétodo. Esto significa que es más fácil generalizarlogical_andsi tiene varias máscaras para AND. Por ejemplo, para y máscarasm1ym2ym3con&, 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
dfanterior, 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_orPara 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.invInternamente llama
__invert__a la serie.np.logical_notEsta es la variante numpy.
Nota,
np.logical_andpuede ser sustituido pornp.bitwise_and,logical_orconbitwise_orylogical_notconinvert.fuente
|, que es equivalente anumpy.bitwise_or, en lugar denumpy.logical_or. ¿Puedo preguntar por qué? ¿No estánumpy.logical_ordiseñ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,oronot) enpandas.Seriesopandas.DataFrames (de manera similar no se puede utilizar ennumpy.arrays con más de un elemento). La razón por la que no puede usarlos es porque invocan implícitamenteboolsus 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.arraysubclase:andtienenp.logical_andortienenp.logical_ornottienenp.logical_notnumpy.logical_xorque no tiene equivalente en Python pero es una operación lógica "exclusiva o"Entonces, esencialmente, uno debe usar (suponiendo
df1ydf2son 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_ando el&operadornp.bitwise_oro el|operadornp.invert(o el aliasnp.bitwise_not) o el~operadornp.bitwise_xoro 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óndeaybson, 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
boolporque el bool se interpretará como enteros en este contexto (por ejemplo,~Falseretornos-1y~Trueretornos-2).fuente