Cómo arreglar “ValueError: 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 (“and” y “or”).

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 “and”

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 “or”

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