Reputation: 3
I have the following function:
def fun1(a):
b=a[0]+a[1]
return(b)
I want to vectorize it using:
fun2 = np.vectorize(fun1,signature='(n,m)->(n,1)')
the input
input=np.array([
[1 ,2],
[3, 4],
[5, 6]])
I need the output like:
fun2(input)=
np.array([[3],[7],[11]])
I know I can do it using np.sum(input,axis=1)
but I am trying to understand the signature so can you help me with the signature?
Edit: I know the function is so simple and it does not need any vectorization but if I am unable to vectorize a simple function I won't be able to vectorize any complex function
understand the signature
Upvotes: 0
Views: 282
Reputation: 231385
In [187]: def fun1(a):
...: b=a[0]+a[1]
...: return(b)
...:
...: fun2 = np.vectorize(fun1,signature='(n)->()')
...:
...: input=np.array([
...: [1 ,2],
...: [3, 4],
...: [5, 6]])
In [188]: fun2(input)
Out[188]: array([ 3, 7, 11])
b
is a scalar, so we can't force the output to be (3,1) shape. You'll have to settle for the (3,)
With your attempt the full traceback (which YOU should have posted) is:
In [191]: fun2 = np.vectorize(fun1,signature='(n,m)->(n,1)')
In [192]: fun2(input)
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
Input In [192], in <cell line: 1>()
----> 1 fun2(input)
File ~\anaconda3\lib\site-packages\numpy\lib\function_base.py:2163, in vectorize.__call__(self, *args, **kwargs)
2160 vargs = [args[_i] for _i in inds]
2161 vargs.extend([kwargs[_n] for _n in names])
-> 2163 return self._vectorize_call(func=func, args=vargs)
File ~\anaconda3\lib\site-packages\numpy\lib\function_base.py:2237, in vectorize._vectorize_call(self, func, args)
2235 """Vectorized call to `func` over positional `args`."""
2236 if self.signature is not None:
-> 2237 res = self._vectorize_call_with_signature(func, args)
2238 elif not args:
2239 res = func()
File ~\anaconda3\lib\site-packages\numpy\lib\function_base.py:2291, in vectorize._vectorize_call_with_signature(self, func, args)
2289 if outputs is None:
2290 for result, core_dims in zip(results, output_core_dims):
-> 2291 _update_dim_sizes(dim_sizes, result, core_dims)
2293 if otypes is None:
2294 otypes = [asarray(result).dtype for result in results]
File ~\anaconda3\lib\site-packages\numpy\lib\function_base.py:1892, in _update_dim_sizes(dim_sizes, arg, core_dims)
1890 num_core_dims = len(core_dims)
1891 if arg.ndim < num_core_dims:
-> 1892 raise ValueError(
1893 '%d-dimensional argument does not have enough '
1894 'dimensions for all core dimensions %r'
1895 % (arg.ndim, core_dims))
1897 core_shape = arg.shape[-num_core_dims:]
1898 for dim, size in zip(core_dims, core_shape):
ValueError: 1-dimensional argument does not have enough dimensions for all core dimensions ('n', '1')
It can't force the b
to 2d. We can do:
In [193]: fun2 = np.vectorize(fun1,signature='(n,m)->(1)')
In [194]: fun2(input)
Out[194]: array([4, 6])
If I add a print(a)
to fun1
we see it just passes the whole 2 array to fun1
, so the effect is simply adding the first 2 rows:
In [196]: fun2(input)
[[1 2]
[3 4]
[5 6]]
Out[196]: array([4, 6])
In [197]: input[0]+input[1]
Out[197]: array([4, 6])
See also
Trying to understand signature in numpy.vectorize
With a corrected fun1
:
In [202]: def fun1(a):
...: print(a)
...: b=a[0]+a[1]
...: return np.array([b])
...:
...: fun2 = np.vectorize(fun1,signature='(n)->(m)')
In [203]: fun2(input)
[1 2]
[3 4]
[5 6]
Out[203]:
array([[ 3],
[ 7],
[11]])
signature
has to match what the function produces, not what you want the result to be. And pay close attention to what vectorize
passes to your function. Guesses and wishes don't count!
Another way of 'vectorizing' this function:
In [205]: np.vectorize(lambda a1,a2: fun1((a1,a2)), otypes=[int])(input[:,0],input[:,1])
(1, 2)
(3, 4)
(5, 6)
Out[205]: array([ 3, 7, 11])
Now you can even pass (3,1) and (3) arrays and get (3,3):
In [206]: np.vectorize(lambda a1,a2: fun1((a1,a2)), otypes=[int])(input[:,0,None],input[:,1])
(1, 2)
(1, 4)
(1, 6)
(3, 2)
(3, 4)
(3, 6)
(5, 2)
(5, 4)
(5, 6)
Out[206]:
array([[ 3, 5, 7],
[ 5, 7, 9],
[ 7, 9, 11]])
And without the vectorize
baggage:
In [207]: input[:,0,None]+input[:,1]
Out[207]:
array([[ 3, 5, 7],
[ 5, 7, 9],
[ 7, 9, 11]])
Upvotes: 1