C贸mo arreglar 鈥淰alueError: The truth value of an array with more than one element is ambiguous. Use a.any() o a.all()”

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

Si ejecutas el siguiente c贸digo, experimentar谩s un ValueError especial:

import numpy as np
a = np.array([1, 2, 3])
b = bool(a)
print(b)

El resultado ser谩 este mensaje de error:

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

Soluci贸n: Usar las funciones de Numpy llamadas logical_and() y logical_or() en lugar de los operadores l贸gicos de Python (鈥渁nd鈥 y 鈥渙r鈥).

Domina los fundamentos y 煤nete al curso “Funciones integradas de Python” aqu铆: https://academy.finxter.com/university/python-built-in-functions-every-python-coder-must-know/

驴Por qu茅 se produce el ValueError?

Muchos programadores que empiezan a aprender Numpy piensan que pueden usar los operadores l贸gicos de Python al escribir c贸digo, pero los creadores de este m贸dulo han decidido que no hay una forma com煤nmente entendida de evaluar un array en un contexto booleano.

Puede significar True si cualquier elemento es True, o True si todos los elementos son True, o True si el array tiene una longitud distinta de cero. Y solo mencionamos tres posibilidades: 隆hay m谩s!

Como los distintos usuarios pueden tener necesidades y objetivos diversos, los desarrolladores se negaron a especular y decidieron lanzar el ValueError cada vez que alguien intentara evaluar un array en un contexto booleano, as铆 que 驴qu茅 dieron a cambio?

Funci贸n logical_and() 鈥 el equivalente de 鈥渁nd鈥

La funci贸n logical_and() es equivalente al operador l贸gico integrado 鈥AND鈥 de Python. Cuando usamos esta funci贸n, el programa devolver谩 un array con valores True y False.

Esta funci贸n tiene dos par谩metros cruciales, es decir, nuestros arrays de entrada, que ponemos despu茅s de la coma (en este ejemplo arr1 < 3 y arr_2 > 3). Veamos el ejemplo:

import numpy as np

arr_1 = np.arange(5)
arr_2 = np.arange(5, 10)
arr_3 = np.array(['First', 'Second', 'Third', 'Fourth', 'Fifth'])

mask = np.logical_and(arr_1 < 3, arr_2 > 3)
print(arr_3[mask])

Salida:

['First' 'Second' 'Third']

El c贸digo imprimi贸 el primer, segundo y tercer elemento del array arr_3, porque comprob贸 nuestras condiciones y result贸 que los tres primeros n煤meros de nuestros arrays cumplen las condiciones al mismo tiempo.

Funci贸n logical_or() 鈥 el equivalente de 鈥渙r鈥

La funcionalidad es la misma que la anterior. Tambi茅n tiene dos par谩metros fundamentales: los arrays de entrada. La 煤nica diferencia est谩 en el comportamiento del c贸digo, despu茅s de todo queremos conseguir algo diferente:

import numpy as np

arr_1 = np.arange(5)
arr_2 = np.arange(5, 10)
arr_3 = np.array(['First', 'Second', 'Third', 'Fourth', 'Fifth'])

mask = np.logical_or(arr_1 >= 3, arr_2 < 3)
print(arr_3[mask])

Como al menos uno de los elementos en las posiciones 4 y 5 de nuestros arrays cumple con nuestra condici贸n, el resultado es el siguiente:

['Fourth' 'Fifth']

And l贸gico con “&” y Or l贸gico con “|”

En lugar de escribir logical_and() o logical_or() podemos usar los s铆mbolos & y |. 脡chale un vistazo a este c贸digo.

import numpy
arr_1 = np.arange(5)
arr_2 = np.arange(5, 10)
arr_3 = np.array(['First', 'Second', 'Third', 'Fourth', 'Fifth'])

# Same functionality as logical_and
mask = np.array((arr_1 < 3) & (arr_2 > 3))
print(arr_3[mask])

# Same functionality as logical_or
mask = np.array((arr_1 >= 3) | (arr_2 < 3))
print(arr_3[mask])

Salida:

['Fourth' 'Fifth']
['First' 'Second' 'Third']

any() y all()

Como estas dos funciones aparecen en el tema, 隆aqu铆 tienes una r谩pida explicaci贸n de lo que hacen en realidad!

La funci贸n any() comprueba si alguno de los elementos es distinto de cero y all() comprueba si todos los elementos son distintos de cero. Estas funciones toman varios par谩metros, pero dos son los m谩s importantes:

  • a -> Array de entrada u objeto que se puede convertir en un array.
  • axis -> Eje o ejes a lo largo de los cuales se realiza una reducci贸n l贸gica de OR. El valor predeterminado (axis=None) es realizar un OR l贸gico sobre todas las dimensiones del array de entrada. axis puede ser negativo, en cuyo caso cuenta desde el 煤ltimo hasta el primer eje.
arr_1 = np.array([[1, 2, 3, 0],[0, 1, 2, 3]])

print('Outputs of function any')
print(np.any(arr_1))
print(np.any(arr_1, axis=0))
print(np.any(arr_1, axis=1))

print('\nOutputs of function all')
print(np.all(arr_1))
print(np.all(arr_1, axis=0))
print(np.all(arr_1, axis=1))

Salida:

Outputs of function any:
True
[ True  True  True  True]
[ True  True]

Outputs of function all:
False
[False  True  True False]
[False False]

Como puedes ver, nuestro script comprob贸 al principio si alg煤n valor a lo largo del eje no es cero.

馃挕 Nota: axis=0 es un eje vertical y axis=1 es un eje horizontal.

Resumen

Hemos aprendido por qu茅 hay un error ValueError cuando queremos usar los operadores l贸gicos integrados en Python (鈥and鈥 y 鈥or鈥) en operaciones l贸gicas cuando usamos arrays.

A continuaci贸n, los dos equivalentes de estos operadores l贸gicos (鈥logical_and鈥 y 鈥logical_or鈥) y una forma a煤n m谩s r谩pida de lograr lo mismo.

Finalmente, se explicaron las funciones any() y all() del m贸dulo Numpy.

Referencias