【问题标题】:Access all elements at given x, y position in 3-dimensional numpy array访问 3 维 numpy 数组中给定 x、y 位置的所有元素
【发布时间】:2016-09-07 00:25:13
【问题描述】:
mat_a = np.random.random((5, 5))
mat_b = np.random.random((5, 5))
mat_c = np.random.random((5, 5))
bigmat = np.stack((mat_a, mat_b, mat_c)) # this is a 3, 5, 5 array

for (x, y, z), value in np.ndenumerate(bigmat):
    print (x, y, z)

在上面的示例中,我如何循环以便仅遍历 5 x 5 数组,并且在每个位置我得到 3 个值,即循环应该运行 25 次,每次,我得到一个包含 3 个值的数组(一个来自 mat_a、mat_b 和 mat_c)

  • 编辑:请注意,我以后需要能够按位置访问元素,即如果 bigmat 被重新调整,应该有一种方法可以根据特定的 y、z 访问元素

【问题讨论】:

  • 搜索python numpy moving sliding rolling window。您可以使用 scikit-image (view_as_windows) 和 scikit-learn (extract_patches) 找到现成的 mde 解决方案。
  • 这是一种使用 ndenumerate 迭代 25 次的方法:[bigmat[:,y,z] for (y,z),v in np.ndenumerate(bigmat[0,...])]
  • this SO answer 处的函数创建一个数组,该数组在迭代期间根据您的规范生成窗口。您的实际数据的形状是什么?
  • @wwii,我的数据的形状是2160 * 4320。当3个这样的数组组合时,得到的形状是3 * 2160 * 4320

标签: python numpy


【解决方案1】:

有一个函数可以为给定的形状生成所有索引,ndindex

for y,z in np.ndindex(bigmat.shape[1:]):
    print(y,z,bigmat[:,y,z])

0 0 [ 0 25 50]
0 1 [ 1 26 51]
0 2 [ 2 27 52]
0 3 [ 3 28 53]
0 4 [ 4 29 54]
1 0 [ 5 30 55]
1 1 [ 6 31 56]
...

对于像这样的简单情况,它并不比双 for range 循环容易得多。也不会更快;但你要求迭代。

另一个迭代器是itertools.product(range(5),range(5))

从时间上看,产品还不错:

In [181]: timeit [bigmat[:,y,z] for y,z in itertools.product(range(5),range(5
     ...: ))]
10000 loops, best of 3: 26.5 µs per loop

In [191]: timeit [bigmat[:,y,z] for (y,z),v in np.ndenumerate(bigmat[0,...])]
     ...: 
10000 loops, best of 3: 61.9 µs per loop

转置和重塑是获取三元组列表(或数组)的最快方法 - 但它也不提供索引:

In [198]: timeit list(bigmat.transpose(1,2,0).reshape(-1,3))
100000 loops, best of 3: 15.1 µs per loop

但同样的操作从np.mgrid(或np.meshgrid)获取索引:

np.mgrid[0:5,0:5].transpose(1,2,0).reshape(-1,2)

(虽然这出奇的慢)

【讨论】:

  • 谢谢@hpaulj,当数组大小为2160 * 4320时会更快吗?
  • 我认为迭代方法没有太大区别。通常,在每次迭代期间迭代操作时,与迭代本身一样昂贵,甚至更多。无论迭代方法如何,做 4000 次都是昂贵的。
【解决方案2】:

西蒙的回答很好。如果您正确地重塑事物,则可以将它们全部放在一个不错的数组中,而无需任何循环。

In [33]: bigmat
Out[33]: 
array([[[ 0.51701737,  0.90723012,  0.42534365,  0.3087416 ,  0.44315561],
        [ 0.3902181 ,  0.59261932,  0.21231607,  0.61440961,  0.24910501],
        [ 0.63911556,  0.16333704,  0.62123781,  0.6298554 ,  0.29012245],
        [ 0.95260313,  0.86813746,  0.26722519,  0.14738102,  0.60523372],
        [ 0.33189713,  0.6494197 ,  0.30269686,  0.47312059,  0.84690451]],

       [[ 0.95974972,  0.09659425,  0.06765838,  0.36025411,  0.91492751],
        [ 0.92421874,  0.31670119,  0.99623178,  0.30394588,  0.30970197],
        [ 0.53590091,  0.04273708,  0.97876218,  0.09686119,  0.78394054],
        [ 0.5463358 ,  0.29239676,  0.6284822 ,  0.96649507,  0.05261606],
        [ 0.91733464,  0.77312656,  0.45962704,  0.06446105,  0.58643379]],

       [[ 0.75161903,  0.43286354,  0.09633492,  0.52275049,  0.40827006],
        [ 0.51816158,  0.05330978,  0.49134325,  0.73652136,  0.14437844],
        [ 0.83833791,  0.2072704 ,  0.18345275,  0.57282927,  0.7218022 ],
        [ 0.56180415,  0.85591746,  0.35482315,  0.94562085,  0.92706479],
        [ 0.2994697 ,  0.99724253,  0.66386017,  0.0121033 ,  0.43448805]]])

重塑事物...

new_bigmat =  bigmat.T.reshape([25,3])

In [36]: new_bigmat
Out[36]: 
array([[ 0.51701737,  0.95974972,  0.75161903],
       [ 0.3902181 ,  0.92421874,  0.51816158],
       [ 0.63911556,  0.53590091,  0.83833791],
       [ 0.95260313,  0.5463358 ,  0.56180415],
       [ 0.33189713,  0.91733464,  0.2994697 ],
       [ 0.90723012,  0.09659425,  0.43286354],
       [ 0.59261932,  0.31670119,  0.05330978],
       [ 0.16333704,  0.04273708,  0.2072704 ],
       [ 0.86813746,  0.29239676,  0.85591746],
       [ 0.6494197 ,  0.77312656,  0.99724253],
       [ 0.42534365,  0.06765838,  0.09633492],
       [ 0.21231607,  0.99623178,  0.49134325],
       [ 0.62123781,  0.97876218,  0.18345275],
       [ 0.26722519,  0.6284822 ,  0.35482315],
       [ 0.30269686,  0.45962704,  0.66386017],
       [ 0.3087416 ,  0.36025411,  0.52275049],
       [ 0.61440961,  0.30394588,  0.73652136],
       [ 0.6298554 ,  0.09686119,  0.57282927],
       [ 0.14738102,  0.96649507,  0.94562085],
       [ 0.47312059,  0.06446105,  0.0121033 ],
       [ 0.44315561,  0.91492751,  0.40827006],
       [ 0.24910501,  0.30970197,  0.14437844],
       [ 0.29012245,  0.78394054,  0.7218022 ],
       [ 0.60523372,  0.05261606,  0.92706479],
       [ 0.84690451,  0.58643379,  0.43448805]])

编辑:要跟踪索引,您可以尝试以下方法(在此处接受其他想法)。 xy_index 中的每一行分别为 new_bigmat 数组中的相应行提供 x,y 值。这个答案不需要任何循环。如果可以接受循环,您可以按照 hpaulj 的回答中的建议在 cmets 或 np.ndindex 中借用 Simon 的建议。

row_index, col_index = np.meshgrid(range(5),range(5))
xy_index = np.array([row_index.flatten(), col_index.flatten()]).T

In [48]: xy_index
Out[48]: 
array([[0, 0],
       [1, 0],
       [2, 0],
       [3, 0],
       [4, 0],
       [0, 1],
       [1, 1],
       [2, 1],
       [3, 1],
       [4, 1],
       [0, 2],
       [1, 2],
       [2, 2],
       [3, 2],
       [4, 2],
       [0, 3],
       [1, 3],
       [2, 3],
       [3, 3],
       [4, 3],
       [0, 4],
       [1, 4],
       [2, 4],
       [3, 4],
       [4, 4]])

【讨论】:

  • 很好的提示。我同意这是在许多情况下的最佳方法。
  • 感谢@user2241910,这看起来是一个很好的答案。但是有一个问题,我现在已经在我的问题中澄清了这一点。我需要根据位置元素 y 和 z 填充一个新数组。既然你重塑了数组,我如何得到这些?
  • 或者new_bigmat[x+5*y]可以访问正确的行。
【解决方案3】:

可以通过切片得到需要的结果,例如:

for x in range(5):
    for y in range(5):
        print (bigmat[:,x,y])

【讨论】:

    【解决方案4】:

    如果您实际上不需要堆叠数组,而只想遍历所有三个数组,逐元素一次numpy.nditer 有效 - 我仍然很模糊它的所有参数我不知道它是否更快,在一个子集上测试它。

    a1 = np.arange(9).reshape(3,3) + 10
    a2 = np.arange(9).reshape(3,3) + 20
    a3 = np.arange(9).reshape(3,3) + 30
    
    c = np.nditer((a1, a2, a3))
    for thing in c:
        print(np.array(thing))
    
    >>> 
    [10 20 30]
    [11 21 31]
    [12 22 32]
    [13 23 33]
    [14 24 34]
    [15 25 35]
    [16 26 36]
    [17 27 37]
    [18 28 38]
    >>>
    

    【讨论】:

      猜你喜欢
      • 2018-08-07
      • 2020-11-23
      • 2016-01-25
      • 2022-08-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-09
      • 1970-01-01
      相关资源
      最近更新 更多