ValueError: el valor de verdad de una matriz con más de un elemento es ambiguo. Utilice a.any () o a.all ()

221

Acabo de descubrir un error lógico en mi código que estaba causando todo tipo de problemas. Inadvertidamente estaba haciendo un AND bit a bit en lugar de un AND lógico .

Cambié el código de:

r = mlab.csv2rec(datafile, delimiter=',', names=COL_HEADERS)
mask = ((r["dt"] >= startdate) & (r["dt"] <= enddate))
selected = r[mask]

A:

r = mlab.csv2rec(datafile, delimiter=',', names=COL_HEADERS)
mask = ((r["dt"] >= startdate) and (r["dt"] <= enddate))
selected = r[mask]

Para mi sorpresa, recibí el mensaje de error bastante críptico:

ValueError: el valor de verdad de una matriz con más de un elemento es ambiguo. Utilice a.any () o a.all ()

¿Por qué no se emitió un error similar cuando uso una operación bit a bit y cómo lo soluciono?

Homunculus Reticulli
fuente
1
Pandas también ofrece documentación para esto
Greg

Respuestas:

164

res una matriz numpy (rec). También r["dt"] >= startdatees una matriz (booleana). Para matrices numpy, la &operación devuelve el elemento -y de las dos matrices booleanas.

Los desarrolladores de NumPy sintieron que no había una forma común de evaluar una matriz en un contexto booleano: podría significar Truesi algún elemento es True, o podría significar Truesi todos los elementos son True, o Truesi la matriz tiene una longitud distinta de cero, solo por nombrar tres posibilidades

Dado que diferentes usuarios pueden tener diferentes necesidades y diferentes suposiciones, los desarrolladores de NumPy se negaron a adivinar y en su lugar decidieron generar un ValueError cada vez que uno intenta evaluar una matriz en un contexto booleano. La aplicación anda dos matrices numpy hace que las dos matrices se evalúen en contexto booleano (llamando __bool__a Python3 o __nonzero__Python2).

Su código original

mask = ((r["dt"] >= startdate) & (r["dt"] <= enddate))
selected = r[mask]

parece correcto Sin embargo, si lo desea and, entonces en lugar de a and busar (a-b).any()o (a-b).all().

unutbu
fuente
2
Tienes razón. El código original era correcto. El error parece estar en otro lugar del código.
Homunculus Reticulli
2
Excelente explicación Sin embargo, implica que NumPy es bastante ineficiente: evalúa completamente ambas matrices booleanas, mientras que una implementación eficiente evaluaría cond1 (i) && cond2 (i) dentro de un solo bucle, y omitirá cond2 a menos que cond1 sea verdadero.
Joachim W
@JoachimWuttke: A pesar de que np.ally np.anyson capaces de cortocircuito, el argumento pasado a él se evalúa antes np.allo np.anytiene la oportunidad de cortocircuito. Para hacerlo mejor, actualmente, tendría que escribir un código C / Cython especializado similar a este .
unutbu
47

Tuve el mismo problema (es decir, indexar con múltiples condiciones, aquí está encontrando datos en un cierto rango de fechas). El (a-b).any()o (a-b).all()parece que no funciona, al menos para mí.

Alternativamente, encontré otra solución que funciona perfectamente para mi funcionalidad deseada ( el valor de verdad de una matriz con más de un elemento es ambiguo cuando intento indexar una matriz ).

En lugar de usar el código sugerido anteriormente, simplemente usar a numpy.logical_and(a,b)funcionaría. Aquí es posible que desee volver a escribir el código como

selected  = r[numpy.logical_and(r["dt"] >= startdate, r["dt"] <= enddate)]
Yeqing Zhang
fuente
34

La razón de la excepción es que andimplícitamente llama bool. Primero en el operando izquierdo y (si el operando izquierdo es True) luego en el operando derecho. Entonces x and yes equivalente a bool(x) and bool(y).

Sin embargo, el boolen un numpy.ndarray(si contiene más de un elemento) arrojará la excepción que ha visto:

>>> import numpy as np
>>> arr = np.array([1, 2, 3])
>>> bool(arr)
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

La bool()llamada está en implícita and, sino también en if, while, or, por lo que cualquiera de los siguientes ejemplos también fallará:

>>> arr and arr
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

>>> if arr: pass
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

>>> while arr: pass
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

>>> arr or arr
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

Hay más funciones y declaraciones en Python que ocultan boolllamadas, por ejemplo, 2 < x < 10es solo otra forma de escribir 2 < x and x < 10. Y la andllamarán bool: bool(2 < x) and bool(x < 10).

El equivalente a nivel de elemento para andsería la np.logical_andfunción, de forma similar podría usarlo np.logical_orcomo equivalente para or.

Para las matrices booleanas - y comparaciones como <, <=, ==, !=,>= y >en NumPy matrices devuelven tablas de NumPy booleanos - también puede utilizar los elementos en cuanto a nivel de bit funciones (y operadores): np.bitwise_and( &operador)

>>> np.logical_and(arr > 1, arr < 3)
array([False,  True, False], dtype=bool)

>>> np.bitwise_and(arr > 1, arr < 3)
array([False,  True, False], dtype=bool)

>>> (arr > 1) & (arr < 3)
array([False,  True, False], dtype=bool)

y bitwise_or( |operador):

>>> np.logical_or(arr <= 1, arr >= 3)
array([ True, False,  True], dtype=bool)

>>> np.bitwise_or(arr <= 1, arr >= 3)
array([ True, False,  True], dtype=bool)

>>> (arr <= 1) | (arr >= 3)
array([ True, False,  True], dtype=bool)

Puede encontrar una lista completa de funciones lógicas y binarias en la documentación de NumPy:

MSeifert
fuente
2

si trabaja con pandaslo que resolvió el problema para mí fue que estaba tratando de hacer cálculos cuando tenía valores de NA, la solución era ejecutar:

df = df.dropna()

Y después de eso el cálculo que falló.

Tomer Ben David
fuente
0

Este mensaje de error escrito también se muestra mientras if-statementse realiza una comparación donde hay una matriz y, por ejemplo, un bool o int. Ver por ejemplo:

... code snippet ...

if dataset == bool:
    ....

... code snippet ...

Esta cláusula tiene un conjunto de datos como matriz y bool es euhm la "puerta abierta" ... Trueo False.

En caso de que la función esté envuelta dentro de un try-statement, recibirá except Exception as error:el mensaje sin su tipo de error:

El valor de verdad de una matriz con más de un elemento es ambiguo. Utilice a.any () o a.all ()

ZF007
fuente
-6

intente esto => numpy.array (r) o numpy.array (yourvariable) seguido del comando para comparar lo que desee.

Anurag Gupta
fuente