我想将任意函数应用于3d- narray作为元素,它使用(三维)数组作为其参数并返回标量。因此,我们应该得到2d-Matrix。
例如:伪代码
A = [[[1,2,3],[4,5,6]],
[[7,8,9],[10,11,12]]]
A.apply_3d_array(sum) ## or apply_3d_array(A,sum) is Okey.
>> [[6,15],[24,33]]
我知道这是可能的循环使用narray。形状函数,但直接索引访问是低效的,正如官方文件所说。有比循环更有效的方法吗?
def chromaticity(pixel):
geo_mean = math.pow(sum(pixel),1/3)
return map(lambda x: math.log(x/geo_mean),pixel )
给定函数实现,我们可以使用NumPy ufuncs
对其进行矢量化,这将一次操作整个输入数组A
,从而避免math
库函数不支持对数组进行矢量化。在这个过程中,我们还引入了非常有效的矢量化工具:NumPy broadcasting
。因此,我们会有这样的实现-
np.log(A/np.power(np.sum(A,2,keepdims=True),1/3))
示例运行和验证
没有lamdba
结构并引入NumPy函数而不是math
库函数的函数实现将看起来像这样-
def chromaticity(pixel):
geo_mean = np.power(np.sum(pixel),1/3)
return np.log(pixel/geo_mean)
使用迭代实现运行示例-
In [67]: chromaticity(A[0,0,:])
Out[67]: array([-0.59725316, 0.09589402, 0.50135913])
In [68]: chromaticity(A[0,1,:])
Out[68]: array([ 0.48361096, 0.70675451, 0.88907607])
In [69]: chromaticity(A[1,0,:])
Out[69]: array([ 0.88655887, 1.02009026, 1.1378733 ])
In [70]: chromaticity(A[1,1,:])
Out[70]: array([ 1.13708257, 1.23239275, 1.31940413])
使用建议的矢量化实现运行示例-
In [72]: np.log(A/np.power(np.sum(A,2,keepdims=True),1/3))
Out[72]:
array([[[-0.59725316, 0.09589402, 0.50135913],
[ 0.48361096, 0.70675451, 0.88907607]],
[[ 0.88655887, 1.02009026, 1.1378733 ],
[ 1.13708257, 1.23239275, 1.31940413]]])
运行时测试In [131]: A = np.random.randint(0,255,(512,512,3)) # 512x512 colored image
In [132]: def org_app(A):
...: out = np.zeros(A.shape)
...: for i in range(A.shape[0]):
...: for j in range(A.shape[1]):
...: out[i,j] = chromaticity(A[i,j])
...: return out
...:
In [133]: %timeit org_app(A)
1 loop, best of 3: 5.99 s per loop
In [134]: %timeit np.apply_along_axis(chromaticity, 2, A) #@hpaulj's soln
1 loop, best of 3: 9.68 s per loop
In [135]: %timeit np.log(A/np.power(np.sum(A,2,keepdims=True),1/3))
10 loops, best of 3: 90.8 ms per loop
这就是为什么在使用数组进行矢量化时总是尝试在NumPy funcs
中推入,并一次处理尽可能多的元素!
apply_along_axis
的设计使这项任务变得容易:
In [683]: A=np.arange(1,13).reshape(2,2,3)
In [684]: A
Out[684]:
array([[[ 1, 2, 3],
[ 4, 5, 6]],
[[ 7, 8, 9],
[10, 11, 12]]])
In [685]: np.apply_along_axis(np.sum, 2, A)
Out[685]:
array([[ 6, 15],
[24, 33]])
它实际上做了
for all i,j:
out[i,j] = func( A[i,j,:])
注意细节。它并不比你自己做迭代快,但它使它更容易。
另一个技巧是将输入重塑为2d,执行更简单的1d迭代,然后重塑结果
A1 = A.reshape(-1, A.shape[-1])
for i in range(A1.shape[0]):
out[i] = func(A1[i,:])
out.reshape(A.shape[:2])
为了更快地完成任务,您需要深入研究函数的核心,并弄清楚如何在多个维度上使用compile numpy操作。在sum
的简单示例中,该函数已经可以在选定的轴上工作。