首页 > 解决方案 > 如何重新索引 3d numpy 数组

问题描述

假设我们有一个 3D 数组,例如:

array = np.arange(8).reshape(2,2, 2) new_array = np.zeros((2, 2, 2))

并假设我们的数组有一些新的随机 x,y,z 索引

x,y,z = np.meshgrid(array, array, array)

重新索引我们的数组的最快方法是什么?

这里给出了一个简单的解决方案:

for x in range(0, 3):
    for y in range(0, 3):
        for z in range(0, 3):
            new_x = x_coord[x,y,z]
            new_y = y_coord[x,y,z]
            new_z = z_coord[x,y,z]

            new_array[x,y,z] = array[new_x, new_y, new_z]

有没有one-liner我不知道的?

编辑

是的,有......非常简单:

vol = np.arange(8).reshape(2,2, 2)
arr = np.arange(2)
x,y,z = np.meshgrid(arr, arr, arr)


print(vol)
print(vol[y, x, z]) ### ---> You have to swap the axes here tho. Does anyone know why?

[[[0 1]
  [2 3]]

 [[4 5]
  [6 7]]]
[[[0 1]
  [2 3]]

 [[4 5]
  [6 7]]]

此外,它非常缓慢。任何想法如何提高性能?

标签: pythonarraysnumpyindexing

解决方案


设置:

In [54]: arr = np.arange(9).reshape(3,3)
In [55]: x = np.random.randint(0,3,(3,3))
In [56]: y = np.random.randint(0,3,(3,3))
In [57]: x
Out[57]: 
array([[2, 0, 1],
       [0, 2, 1],
       [0, 0, 1]])
In [58]: y
Out[58]: 
array([[0, 0, 0],
       [0, 1, 1],
       [0, 1, 0]])

这些索引数组的最简单应用:

In [59]: arr[x,y]
Out[59]: 
array([[6, 0, 3],
       [0, 7, 4],
       [0, 1, 3]])

迭代等价物:

In [60]: out = np.empty_like(arr)
In [61]: for i in range(3):
    ...:     for j in range(3):
    ...:         out[i,j] = arr[x[i,j], y[i,j]]
    ...:         
In [62]: out
Out[62]: 
array([[6, 0, 3],
       [0, 7, 4],
       [0, 1, 3]])

您的代码不一样,因为它在迭代时修改了源数组:

In [63]: arr1 = arr.copy()
In [64]: for i in range(3):
    ...:     for j in range(3):
    ...:         arr1[i,j] = arr1[x[i,j], y[i,j]]
    ...:         
In [65]: arr1
Out[65]: 
array([[6, 6, 3],
       [6, 7, 7],
       [6, 6, 6]])

没有简单的等价物。


您可以将索引与arr[x_coord,y_coord,z_coord]一个索引数组一起广播。它们都具有相同的形状,这是微不足道的。

In [68]: x1 = np.random.randint(0,3,(2,4))
In [69]: x1
Out[69]: 
array([[2, 0, 2, 0],
       [0, 0, 0, 2]])
In [70]: arr[x1,x1]
Out[70]: 
array([[8, 0, 8, 0],
       [0, 0, 0, 8]])

从数组中选择随机值的一种更简单的方法是创建随机行和列选择器,并用于ix_创建一起广播的数组:

In [71]: x1 = np.random.randint(0,3,(3))
In [72]: y1 = np.random.randint(0,3,(3))

In [75]: np.ix_(x1,y1)
Out[75]: 
(array([[2],
        [1],
        [1]]), array([[2, 2, 1]]))
In [76]: arr[np.ix_(x1,y1)]
Out[76]: 
array([[8, 8, 7],
       [5, 5, 4],
       [5, 5, 4]])

几乎听起来您只想打乱数组的值,例如:

In [95]: arr
Out[95]: 
array([[0, 1, 2],
       [3, 4, 5],
       [6, 7, 8]])
In [96]: np.random.shuffle(arr.ravel())
In [97]: arr
Out[97]: 
array([[0, 1, 2],
       [7, 4, 3],
       [6, 5, 8]])

推荐阅读