我有像a = np.zeros((100,100, 20))
这样的3D numpy数组。我想对涉及x,y
轴上所有元素的每个z
位置执行操作,结果存储在b = np.zeros((100,100))
之类的数组中,位于相同的x,y
上位置。
现在我正在使用for循环:
d_n = np.array([...]) # a parameter with the same shape as b
for (x,y), v in np.ndenumerate(b):
C = a[x,y,:]
### calculate some_value using C
minv = sys.maxint
depth = -1
C = a[x,y,:]
for d in range(len(C)):
e = 2.5 * float(math.pow(d_n[x,y] - d, 2)) + C[d] * 0.05
if e < minv:
minv = e
depth = d
some_value = depth
if depth == -1:
some_value = len(C) - 1
###
b[x,y] = some_value
现在的问题是这个操作比其他人用pythonic方式慢得多 。 c = b * b
(我实际上是对这个函数进行了分析,它比使用numpy内置函数和向量化函数的其他元素慢了大约2个数量级,超过相似数量的元素)
如何改善将3D阵列映射到2D阵列的此类功能的性能?
答案 0 :(得分:2)
在3D图像中通常做的是将Z
轴交换到第一个索引:
>>> a = a.transpose((2,0,1))
>>> a.shape
(20, 100, 100)
现在您可以轻松地在Z轴上进行迭代:
>>> for slice in a:
do something
此处的slice
将是您的3D矩阵的100x100
个分数。此外,通过转置,您可以通过索引第一个轴直接访问每个2D切片。例如,a[10]
将为您提供第11个2D 100x100
切片。
奖励:如果您连续存储数据,而不进行转置(或使用a = np.ascontiguousarray(a.transpose((2,0,1)))
转换为连续数组,则对2D切片的访问速度会更快,因为它们会在内存中连续映射。
答案 1 :(得分:0)
显然你想要摆脱明确的for
循环,但我认为这是否可行取决于你用C做的计算。作为一个简单的例子,
a = np.zeros((100,100, 20))
a[:,:] = np.linspace(1,20,20) # example data: 1,2,3,.., 20 as "z" for every "x","y"
b = np.sum(a[:,:]**2, axis=2)
将100
100
数组b
填充a
的平方“z”值之和,即1 + 4 + 9 + .. 。+ 400 = 2870。
答案 2 :(得分:0)
如果你的内部计算足够复杂,并且不适合矢量化,那么你的迭代结构是好的,并且对计算时间没有显着贡献
for (x,y), v in np.ndenumerate(b):
C = a[x,y,:]
...
for d in range(len(C)):
... # complex, not vectorizable calc
...
b[x,y] = some_value
在前2个维度中似乎没有特殊的结构,所以您也可以将其视为2D映射到1D,例如将(N,20)
数组映射到(N,)
数组。这不会加速任何事情,但可能有助于突出问题的基本结构。
一步是专注于加快C
到some_value
的计算速度。有cumsum
和cumprod
等函数可以帮助您对向量进行顺序计算。 cython
也是一个很好的工具。
另一种方法是查看是否可以同时对N
值执行内部计算。换句话说,如果你必须迭代,最好在最小的维度上这样做。
从某种意义上说,这是一个非答案。但是,如果不完全了解some_value
和C
的{{1}},我认为我们无法做得更多。
似乎可以同时为所有点计算d_n
:
e
乍看之下,e = 2.5 * float(math.pow(d_n[x,y] - d, 2)) + C[d] * 0.05
E = 2.5 * (d_n[...,None] - np.arange(a.shape[-1]))**2 + a * 0.05 # (100,100,20)
E.min(axis=-1) # smallest value along the last dimension
E.argmin(axis=-1) # index of where that min occurs
似乎是您想要的E.argmin
值(如果需要,可以针对某些边界条件进行调整)。
我没有真实的b
和a
数组,但是对于简单的测试数组,此d_n
与您的E.argmin(-1)
相匹配,加速度为66倍。
答案 3 :(得分:0)
如何改善将3D阵列映射到2D阵列的此类功能的性能?
Numpy中的许多功能都是&#34;还原&#34;函数 * ,例如sum
,any
,std
等。如果您提供除axis
以外的None
参数这样一个函数,它将减少该轴上的数组的尺寸。对于您的代码,如果您首先以矢量化方式计算argmin
,则可以使用e
函数:
d = np.arange(a.shape[2])
e = 2.5 * (d_n[...,None] - d)**2 + a*0.05
b = np.argmin(e, axis=2)
[...,None]
的索引用于参与broadcasting。 e
中的值是浮点值,因此与sys.maxint
进行比较有点奇怪,但是你去了:
I, J = np.indices(b.shape)
b[e[I,J,b] >= sys.maxint] = a.shape[2] - 1
*严格地说,缩减函数的格式为reduce(operator, sequence)
,因此技术上不是std
和argmin