迭代器的数量取决于np.nditer的变量

时间:2019-06-29 22:06:23

标签: 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 = np.float32)
        variances.append(variance)
    else:
        variances.append(float("-inf"))

其中cost_surfaceS是包含我所有的numpy数组的列表。问题在于,这段代码适用于创建的3个numpy数组,并且我想更改“ a,s,m”,以使迭代器的数量取决于创建的numpy数组的数量(即{{1} })。有办法吗?

2 个答案:

答案 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条件处理,该条件避免了计算至少包含一个无穷大值的数组的方差。