When a function doesn't work in np.vectorize
, it's a good idea to verify what the argument is.
Let's add a type
print to the function:
In [36]: def func(y):
...: print(type(y))
...: return sum(x**(-y) for x in range(1, 10))
...:
In the list comprehension, Python int
are passed:
In [37]: func(3)
<class 'int'>
Out[37]: 1.1965319856741932
with the vectorized
version:
In [40]: vect_func(3)
<class 'numpy.int64'>
Traceback (most recent call last):
File "<ipython-input-40-65e2816d8003>", line 1, in <module>
vect_func(3)
File "/usr/local/lib/python3.8/dist-packages/numpy/lib/function_base.py", line 2163, in __call__
return self._vectorize_call(func=func, args=vargs)
File "/usr/local/lib/python3.8/dist-packages/numpy/lib/function_base.py", line 2241, in _vectorize_call
ufunc, otypes = self._get_ufunc_and_otypes(func=func, args=args)
File "/usr/local/lib/python3.8/dist-packages/numpy/lib/function_base.py", line 2201, in _get_ufunc_and_otypes
outputs = func(*inputs)
File "<ipython-input-36-311d525a60ba>", line 3, in func
return sum(x**(-y) for x in range(1, 10))
File "<ipython-input-36-311d525a60ba>", line 3, in <genexpr>
return sum(x**(-y) for x in range(1, 10))
ValueError: Integers to negative integer powers are not allowed.
y
is not a python int
, it is a numpy
int.
In [41]: func(np.int64(3))
<class 'numpy.int64'>
Traceback (most recent call last):
File "<ipython-input-41-c34830937ffd>", line 1, in <module>
func(np.int64(3))
File "<ipython-input-36-311d525a60ba>", line 3, in func
return sum(x**(-y) for x in range(1, 10))
File "<ipython-input-36-311d525a60ba>", line 3, in <genexpr>
return sum(x**(-y) for x in range(1, 10))
ValueError: Integers to negative integer powers are not allowed.
If we deliberately pass Python int
it works:
In [42]: vect_func(np.array([1,2,3], object))
<class 'int'>
<class 'int'>
<class 'int'>
<class 'int'>
Out[42]: array([2.82896825, 1.53976773, 1.19653199])
np.vectorize
can be handy when passing several arrays to a scalar function, and you want to take advantage of broadcasting
. But for a list, or lists that can be zipped, it doesn't add anything to a list comprehension - not even speed.
And as this case illustrates, it has some gotchas than can catch the novice (and even more experienced users). Here it's the nature of the input. For many other SO questions, it's nature of the return value (the automatic otypes
).