python – Error when passing an array of NumPy to a function

Question:

I have defined a function in Python that works correctly for scalar values:

>>> def signo(x):
...   if x < 0:
...     return -1
...   elif x > 0:
...     return 1
...   else:
...     return 0
...
>>> signo(10)
1
>>> signo(-5)
-1

But when I pass it an array of NumPy, it fails with a ValueError :

>>> import numpy as np
>>> t = np.arange(-5, 5)
>>> t
array([-5, -4, -3, -2, -1,  0,  1,  2,  3,  4])
>>> signo(t)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in signo
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

Why does this happen?

Answer:

In this case the error message clearly explains the problem: "the truth value of an array of more than one element is ambiguous". At the moment Python has to evaluate this conditional:

if x < 0:  # x es ahora array([-5, -4, -3, -2, -1,  0,  1,  2,  3,  4])

it cannot return neither True nor False , because there are elements of the array that meet the condition and elements that do not. This is a very typical problem.

Supposing that we want another array, the same size as the input one, with True or False values ​​depending on whether the corresponding element meets the condition or not , there would be two ways to solve it:

1) Implement all the logic internally: it would have to be evaluated in a loop for each of the elements of the array. An implementation would be this:

>>> def signo(x):
...   x = np.atleast_1d(x)  # Convertimos a array
...   sgn = np.zeros_like(x)
...   for ii in range(len(sgn)):
...     if x[ii] < 0:
...       sgn[ii] = -1
...     elif x[ii] > 0:
...       sgn[ii] = 1
...     else:
...       pass  # sgn[ii] ya vale 0
...   return sgn
...
>>> signo(10)
array([1])
>>> signo(-5)
array([-1])
>>> signo(t)
array([-1, -1, -1, -1, -1,  0,  1,  1,  1,  1])

2) Vectorize the function, using np.vectorize . Note that this is how the scalar case is handled in a more elegant way:

>>> def signo(x):
...   if x < 0:
...     return -1
...   elif x > 0:
...     return 1
...   else:
...     return 0
...
>>> signo = np.vectorize(signo)  # Vectorizamos la función
>>> signo(10)
array(1)
>>> signo(-5)
array(-1)
>>> signo(t)
array([-1, -1, -1, -1, -1,  0,  1,  1,  1,  1])

In this specific problem the recommendation to use .any() or .all() does not work, but on another occasion they can be useful functions.

Scroll to Top