Reputation:
I'm trying to do something like the following
import numpy as np
arr = np.array([0,1,2,3])
fn = lambda x: np.array([x/2,x*2])
res = np.apply_along_axis(fn,0,arr)
That is, I want to use np.apply_along_axis
with a function that returns an array rather than a single value. However, this results in the following error.
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.5/site-packages/numpy/lib/shape_base.py", line 117, in apply_along_axis
outarr[tuple(i.tolist())] = res
ValueError: could not broadcast input array from shape (2,4) into shape (2)
While I would expect the outcome to be equivalent to:
res = np.array([[0.0,0],[0.5,2],[1.0,4],[1.5,6]])
Note that my actual use case is more complicated than the fn
given. I would like to know whether there is a way in general to use np.apply_along_axis
with a function that returns an array, or whether there is a different (numpythonic) way to achieve the same thing.
Thanks!
Upvotes: 1
Views: 1038
Reputation: 249163
This sort of thing--applying a regular Python function along an array--is basically the same as a for
loop. It's not going to be very fast, even if you use NumPy functions to invoke your function. So just keep it simple:
arr = np.array([0,1,2,3])
fn = lambda x: [x/2,x*2]
res = np.array(list(map(fn, arr)))
Or if you care about performance:
arr = np.array([0,1,2,3])
funcs = [lambda x: x/2.0, lambda x: x*2.0]
res = np.empty((len(arr), len(funcs)))
for i, func in enumerate(funcs):
res[:,i] = func(arr)
This second way is much faster, so long as you have more rows in the array than the number of functions to apply. This is because you only loop a few times, using NumPy vectorized code to apply each function to the entire input at once, rather than looping over the input rows one by one.
Upvotes: 2
Reputation: 13218
A workaround I have found is to stack the results, to make your lambda return a 1D array instead of a 2D one:
arr = np.array([0, 1, 2, 3])
fn = lambda x: np.hstack([x/2, x*2])
res = np.apply_along_axis(fn, 0, arr)
and then you can reshape res
as you want
Upvotes: 2