Python 取决于np.nditer变量的迭代器数
我必须迭代numpy数组,这些数组的数目在程序的每次迭代中都是不同的。目标是计算这些数组中相同元素之间的方差。以下是我编写的代码:Python 取决于np.nditer变量的迭代器数,python,arrays,numpy,Python,Arrays,Numpy,我必须迭代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
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数组数量的迭代器数量(即
len(cost_surfaceS)
)。这是一种方法吗?我同意@Bickknght的观点,即不需要拆包。处理未知或数量可变的元素时,不要使用解包
In [57]: alist = [np.arange(10), np.arange(10,20), np.arange(20,30)]
制作一个数组列表,其中我们不需要ravel
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))
将此与直接列表zip迭代进行比较:
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)
不同之处在于,nditer
生成0d数组而不是标量。因此元素有一个形状((0,)
)和dtype
。或者在某些情况下,您希望修改数组(但必须将它们定义为read/write
),否则nditer
不会提供任何真正的优势
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)
如果可以避免Python级别的循环,那么速度会快得多:
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
的另一个重要区别是,它以一种简单的方式在所有元素上迭代—实际上,它是执行ravel:
列出二维阵列
In [81]: alist = [np.arange(10.).reshape(2,5), np.arange(10,20.).reshape(2,5), np.arange(20,30.).reshape(2,5)]
普通迭代在第一个维度上运行-在本例中为2,因此压缩的元素是数组:
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
生成的元组与1d数组中的元组相同。有些情况下可以,但如果不需要,则很难避免
In [83]: 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.))
正如@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条件处理,以避免计算至少包含一个无穷大值的数组的方差。只需将用于np.nditer(…)
(并去掉下一行)?感谢您的回答,这确实非常容易(而且可能)不幸的是,我将无法在接下来的10天内对其进行测试,但对于“-inf”,我将尝试使用堆栈函数,因为这是最快的,如果它不起作用,则使用简单的“if”我想zip函数的条件应该有效。您可能想问一个新问题,重点是如何以“矢量化”的方式处理-inf
值。遇到inf
时的默认行为是发出警告,然后返回np.nan
。我现在还没有清醒到能够解决这个问题。