Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Applying a function to a 3D array in numpy

I have a 3D numpy.ndarray (think of an image with RGB) like

a = np.arange(12).reshape(2,2,3)
'''array(
  [[[ 0,  1,  2], [ 3,  4,  5]],
   [[ 6,  7,  8], [ 9, 10, 11]]])'''

and a function that handles a list input;

my_sum = lambda x: x[0] + x[1] + x[2]

What should I do to apply this function to each pixel? (or each 1D element of the 2D array)

What I have tried

np.apply_along_axis

This question is the kind of same as mine. So, I first tried it.

np.apply_along_axis(my_sum, 0, a.T).T #EDIT np.apply_along_axis(my_sum, -1, a) is better

at first, I thought this was the solution but this was too slow, because np.apply_along_axis is not for speed

np.vectorize

I applied np.vetorize to my_func.

vector_my_func = np.vectorize(my_sum)

However, I have no idea even on how this vectorized function can be called.

vector_my_func(0,1,2) 
#=> TypeError: <lambda>() takes 1 positional argument but 3 were given

vector_my_func(np.arange(3)) 
#=> IndexError: invalid index to scalar variable.

vector_my_func(np.arange(12).reshape(4,3)) 
#=> IndexError: invalid index to scalar variable.

vector_my_func(np.arange(12).reshape(2,2,3)) 
#=> IndexError: invalid index to scalar variable.

I am totally at loss on how this should be done.

EDIT

benchmark results for suggested methods. (used jupyter notebook and restarted kernel for each test)

a = np.ones((1000,1000,3))
my_sum = lambda x: x[0] + x[1] + x[2]
my_sum_ellipsis = lambda x: x[..., 0] + x[..., 1] + x[..., 2]
vector_my_sum = np.vectorize(my_sum, signature='(i)->()')
%timeit np.apply_along_axis(my_sum, -1, a)
#1 loop, best of 3: 3.72 s per loop

%timeit vector_my_sum(a)
#1 loop, best of 3: 2.78 s per loop

%timeit my_sum(a.transpose(2,0,1))
#100 loops, best of 3: 12 ms per loop

%timeit my_sum_ellipsis(a)
#100 loops, best of 3: 12.2 ms per loop

%timeit my_sum(np.moveaxis(a, -1, 0))
#100 loops, best of 3: 12.2 ms per loop
like image 240
Allosteric Avatar asked Oct 25 '25 07:10

Allosteric


1 Answers

One option is to transpose the numpy array, swap the third axis to the first, and then you can apply the function directly to it:

my_sum(a.transpose(2,0,1))

#array([[ 3, 12],
#       [21, 30]])

Or rewrite the sum function as:

my_sum = lambda x: x[..., 0] + x[..., 1] + x[..., 2]
my_sum(a)
#array([[ 3, 12],
#       [21, 30]])
like image 121
Psidom Avatar answered Oct 28 '25 01:10

Psidom