将函数应用于numpy中的3D数组

时间:2017-03-27 23:43:14

标签: python numpy image-processing matrix

我有一个3D numpy.ndarray(想想带RGB的图像),如

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

和处理列表输入的函数;

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

如何将此功能应用于每个像素?(或2D数组的每个1D元素)

我尝试了什么

np.apply_along_axis

This question和我的一样。所以,我先试了一下。

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

起初,我认为这是解决办法,但这太慢了,因为np.apply_along_axis is not for speed

np.vectorize

我将np.vetorize应用于my_func。

vector_my_func = np.vectorize(my_sum)

但是,我甚至不知道如何调用这个向量化函数。

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.

我完全不知道应该怎么做。

修改

建议方法的基准测试结果。 (使用jupyter笔记本并为每次测试重新启动内核)

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

2 个答案:

答案 0 :(得分:4)

一个选项是转置numpy数组,将第三个轴交换到第一个轴,然后你可以直接将函数应用于它:

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

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

或者将sum函数重写为:

my_sum = lambda x: x[..., 0] + x[..., 1] + x[..., 2]
my_sum(a)
#array([[ 3, 12],
#       [21, 30]])

答案 1 :(得分:1)

从numpy 1.12开始,vectorize获得了signature个参数。所以你可以用它作为:

my_sum = lambda x: x[0] + x[1] + x[2]
vector_my_sum = np.vectorize(my_sum, signature='(i)->()')  # vector to scalar
vector_my_sum(a)

不幸的是,这是一个比普通vectorize慢得多的代码路径,它在1.12中至少运行C中的for循环。

在我的计算机上,使用numpy master,这比apply_along_axis快了大约10%(尽管自{1.1}}以来apply_along_axis已大幅改变了实施情况。