我必须遍历numpy数组,该数组的数量在程序的每次迭代中都可能不同。目的是计算这些数组的相同元素之间的方差。这是我写的代码:
for a,s,m in np.nditer([cost_surfaceS[i].ravel() for i in range(0,len(cost_surfaceS),1)]):
arr = [a, s, m]
if(float(arr[0]) != float("-inf")):
variance = np.var(arr,dtype = np.float32)
variances.append(variance)
else:
variances.append(float("-inf"))
其中cost_surfaceS是包含我所有的numpy数组的列表。问题在于,这段代码适用于创建的3个numpy数组,并且我想更改“ a,s,m”,以使迭代器的数量取决于创建的numpy数组的数量(即{{1} })。有办法吗?
答案 0 :(得分:1)
我同意@Bickknght所说的拆包是不必要的。处理未知或可变数量的元素时,请勿使用event loop
。
unpacking
列出不需要In [57]: alist = [np.arange(10), np.arange(10,20), np.arange(20,30)]
的数组。
ravel
将此与直接列表zip迭代进行比较:
In [58]: for arr in np.nditer(alist):
...: print(arr)
...:
(array(0), array(10), array(20))
(array(1), array(11), array(21))
(array(2), array(12), array(22))
(array(3), array(13), array(23))
(array(4), array(14), array(24))
(array(5), array(15), array(25))
(array(6), array(16), array(26))
(array(7), array(17), array(27))
(array(8), array(18), array(28))
(array(9), array(19), array(29))
区别在于In [59]: for arr in zip(*alist):
...: print(arr)
...:
(0, 10, 20)
(1, 11, 21)
(2, 12, 22)
(3, 13, 23)
(4, 14, 24)
(5, 15, 25)
(6, 16, 26)
(7, 17, 27)
(8, 18, 28)
(9, 19, 29)
生成0d数组而不是标量。因此,元素具有形状(nditer
)和(0,)
。或者在某些情况下要修改数组(但必须将它们定义为dtype
。否则,read/write
并没有任何真正的优势。
nditer
如果可以避免Python级别循环,事情将会更快:
In [62]: %%timeit
...: ll = []
...: for arr in np.nditer(alist):
...: ll.append(np.var(arr))
...:
539 µs ± 17.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
In [63]: %%timeit
...: ll = []
...: for arr in zip(*alist):
...: ll.append(np.var(arr))
...:
524 µs ± 3.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
我没有尝试测试In [65]: np.stack(alist,1)
Out[65]:
array([[ 0, 10, 20],
[ 1, 11, 21],
[ 2, 12, 22],
[ 3, 13, 23],
[ 4, 14, 24],
[ 5, 15, 25],
[ 6, 16, 26],
[ 7, 17, 27],
[ 8, 18, 28],
[ 9, 19, 29]])
In [66]: np.var(np.stack(alist,1),axis=1)
Out[66]:
array([66.66666667, 66.66666667, 66.66666667, 66.66666667, 66.66666667,
66.66666667, 66.66666667, 66.66666667, 66.66666667, 66.66666667])
In [67]: timeit np.var(np.stack(alist,1),axis=1)
66.7 µs ± 1.47 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
。
===
与-inf
的另一个重要区别。它以扁平的方式在所有元素上进行迭代-实际上是在做杂事:
列出二维数组。
nditer
普通迭代在第一维上进行操作-在这种情况下为2,因此压缩后的元素为数组:
In [81]: alist = [np.arange(10.).reshape(2,5), np.arange(10,20.).reshape(2,5), np.arange(20,30.).reshape(2,5)]
In [82]: for arr in zip(*alist):
...: print(arr)
...:
(array([0., 1., 2., 3., 4.]), array([10., 11., 12., 13., 14.]), array([20., 21., 22., 23., 24.]))
(array([5., 6., 7., 8., 9.]), array([15., 16., 17., 18., 19.]), array([25., 26., 27., 28., 29.]))
生成与一维数组中相同的元组。某些情况下还可以,但是如果您不想要它,就很难避免。
nditer
答案 1 :(得分:0)
{@ {3}}是一种解决方案,如@hpaulj所述。使用2d数组而不是1d数组仅需要使用此函数的两倍,如以下代码所示:
variances = []
for arr in zip(*cost_surfaceS):
for element in zip(*arr):
if(float("-inf") not in element):
variance = np.var(element, dtype=np.float32)
variances.append(variance)
else:
variances.append(float("-inf"))
-inf
的值由if条件处理,该条件避免了计算至少包含一个无穷大值的数组的方差。