简体   繁体   English

Python:基于具有第三维索引的相应数组将2D阵列拉伸成3D

[英]Python: Stretch 2D array into 3D based on corresponding array with 3rd-dimension index

Lets say I have some 2D array a = np.ones((3,3)) 假设我有一些2D数组a = np.ones((3,3))

I want to stretch this array into 3 dimensions. 我想将这个数组拉伸成3维。 I have array b , the same size as a , that provides the index in the 3rd dimension that each corresponding element in a needs to go too. 我有阵列b ,大小相同a ,其提供在所述第三尺寸,在每个对应的元素的索引a需要去了。

I also have 3D array c that is filled with NaNs. 我也有充满NaN的3D阵列c This is the array that the information from a should be put into. 这是应该放入a的信息的数组。 The remaining blank spaces that do not get "filled: can remain NaNs. 剩余的空白空间没有被填满:可以保留NaNs。

>>> a = np.ones((3,3))
>>> b = np.random.randint(0,3,(3,3))
>>> c = np.empty((3,3,3))*np.nan
>>> 
>>> a
array([[ 1.,  1.,  1.],
       [ 1.,  1.,  1.],
       [ 1.,  1.,  1.]])
>>> b
array([[2, 2, 2],
       [1, 0, 2],
       [1, 0, 0]])
>>> c
array([[[ nan,  nan,  nan],
        [ nan,  nan,  nan],
        [ nan,  nan,  nan]],

       [[ nan,  nan,  nan],
        [ nan,  nan,  nan],
        [ nan,  nan,  nan]],

       [[ nan,  nan,  nan],
        [ nan,  nan,  nan],
        [ nan,  nan,  nan]]])

So, in the above example, I would want to end up with c[0,0,2] = 1. 所以,在上面的例子中,我想最终得到c [0,0,2] = 1。

I know I probably do this with some nested loops, but ideally I want this done in a more efficient/vectorized way. 我知道我可能会用一些嵌套循环来做这件事,但理想情况下我希望以更高效/矢量化的方式完成。

You can use fancy indexing as this, assuming the largest value in b is always less than c.shape[2] : 你可以使用花式索引,假设b的最大值总是小于c.shape[2]

n1, n2 = a.shape
c[np.arange(n1)[:,None], np.arange(n2), b] = a

c
#array([[[ nan,  nan,   1.],
#        [ nan,  nan,   1.],
#        [ nan,  nan,   1.]],

#       [[ nan,   1.,  nan],
#        [  1.,  nan,  nan],
#        [ nan,  nan,   1.]],

#       [[ nan,   1.,  nan],
#        [  1.,  nan,  nan],
#        [  1.,  nan,  nan]]])

Here we use integer arrays for all dimensions to trigger advanced indexing , and the three arrays are broadcasted against each other as follows ( here we use numpy.broacast_arrays to visualize this ): 这里我们对所有维度使用整数数组来触发高级索引 ,并且三个数组相互广播如下( 这里我们使用numpy.broacast_arrays来可视化 ):

i, j, k = np.broadcast_arrays(np.arange(3)[:,None], np.arange(3), b)

print("first dimension index: ")
print(i)
print("second dimension index: ")
print(j)
print("third dimension index: ")
print(k)

first dimension index: 
[[0 0 0]
 [1 1 1]
 [2 2 2]]
second dimension index: 
[[0 1 2]
 [0 1 2]
 [0 1 2]]
third dimension index: 
[[2 2 2]
 [1 0 2]
 [1 0 0]]

Now the advanced indexing goes as (0, 0, 2), (0, 1, 2), (0, 2, 2) ... ,ie pick one value from each array at the same positions to form an index for an element: 现在,高级索引为(0,0,2),(0,1,2),(0,2,2)...,即从相同位置的每个数组中选取一个值,以形成一个索引。元件:


Some testing cases: 一些测试用例:

c[0,0,2]
#1.0

c[0,1,2]
#1.0

c[2,1,0]
#1.0

Ok, so this feels like a total hack, but does the trick: 好的,所以这感觉就像一个完全黑客,但是诀窍是:

a = np.ones((3,3))
b = np.array([[2, 2, 2],
              [1, 0, 2],
              [1, 0, 0]])
c = np.empty((3,3,3))*np.nan

z_coords = np.arange(3)

c[z_coords[None, None, :] == b[..., None]] = a.ravel()

What I do is create an boolean indexing array that is true for the indices we want to assign, and then assign these. 我所做的是创建一个布尔索引数组,对于我们想要分配的索引是真的,然后分配这些。

array([[[ nan,  nan,   1.],
        [ nan,  nan,   1.],
        [ nan,  nan,   1.]],

       [[ nan,   1.,  nan],
        [  1.,  nan,  nan],
        [ nan,  nan,   1.]],

       [[ nan,   1.,  nan],
        [  1.,  nan,  nan],
        [  1.,  nan,  nan]]])

A slower but perhaps clearer option: 一个较慢但可能更清晰的选择:

x, y = np.indices(c.shape[:2])
c[x, y, b] = a  # same as looping over c[x[i,j], y[i,j], b[i,j]] = a[i,j]

The trick is to produce 3 arrays of indices all with the same shape - one for each dimension of c . 诀窍是产生3个具有相同形状的索引数组 - 每个c一个维度。

The accepted answer is doing essentially this, but taking advantage of broadcasting 接受的答案基本上是这样做,但利用广播

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM