2d数组作为3d数组的索引

时间:2020-02-17 16:22:37

标签: python arrays numpy

我有一个具有8000x64元素的2D数组(C),一个具有8000x1元素的1D数组和另一个具有1x64元素的1D数组(d)。 索引i的每一行(其中s [i]为True)应与向量d相加。 效果很好:

Opel AG

现在,我在C,s和d上添加了一个维,并且以上逻辑将应用于附加维的每个元素。

下面的代码可以实现我想要的,但是非常慢。

C[s == True] += d

在没有for循环的情况下,是否有一种麻木的方法来做到这一点?

3 个答案:

答案 0 :(得分:2)

在开始时添加额外的尺寸会更容易:

In [376]: C = np.zeros((4,2,3),int)                                                            
In [377]: s = np.array([[0,0],[0,1],[1,0],[1,1]],bool)                                         
In [378]: d = np.arange(1,13).reshape(4,3)                                                     
In [379]: C.shape, s.shape, d.shape                                                            
Out[379]: ((4, 2, 3), (4, 2), (4, 3))
In [380]: I,J = np.nonzero(s)                                                                  
In [381]: I,J                                                                                  
Out[381]: (array([1, 2, 3, 3]), array([1, 0, 0, 1]))

In [383]: C[I,J]=d[I]                                                                          
In [384]: C                                                                                    
Out[384]: 
array([[[ 0,  0,  0],
        [ 0,  0,  0]],

       [[ 0,  0,  0],
        [ 4,  5,  6]],

       [[ 7,  8,  9],
        [ 0,  0,  0]],

       [[10, 11, 12],
        [10, 11, 12]]])

您的方式:

In [385]: C = np.zeros((4,2,3),int)                                                            
In [386]: for i in range(4): 
     ...:     C[i,:,:][s[i,:]] += d[i,:] 
     ...:                                                                                      
In [387]: C                                                                                    
Out[387]: 
array([[[ 0,  0,  0],
        [ 0,  0,  0]],

       [[ 0,  0,  0],
        [ 4,  5,  6]],

       [[ 7,  8,  9],
        [ 0,  0,  0]],

       [[10, 11, 12],
        [10, 11, 12]]])

答案 1 :(得分:1)

由于numpy索引的工作方式,在第一个示例中,s选择了C的相关行。要在3D情况下执行相同的操作,必须将C重塑为(8000*3, 64),并将s重塑为(8000*3, 1)。现在唯一的问题是让d来说明每个三维维度中不同的行数,这可以通过np.repeat完成。

第一部分是

C2 = np.swapaxes(C, -1, 1).reshape(-1, 64)

这效率极低,因为它会复制整个阵列。如果C首先具有形状(3, 8000, 64),则是更好的安排。然后,您只需要拉开前两个轴即可获得正确的形状和内存布局,而无需复制数据。

repeats = np.count_nonzero(s, axis=0)
C.reshape(-1, 64)[s.ravel()] += np.repeat(d, repeats, axis=0)

由于在这种情况下,整形操作会返回一个视图,因此索引应该可以正常工作以就地增加。我认为这种方法不一定很好,因为它在新维度的相应元素中将d的每一行复制为s非零的次数。

答案 2 :(得分:0)

这是我建议的@hpaulj方法的实现。请注意,我不想从他那里得到荣誉,因此请标记他的回答,而不是我的正确。只想分享我的所作所为。

import numpy as np
import numpy.random as npr

C = np.zeros((100, 8000, 64), dtype=int)
s = np.zeros((100, 8000), dtype=bool)
d = np.zeros((100, 64), dtype=int)

C[:,:,:] = npr.randint(50, size=C.shape)
s[:,:] = npr.randint(3, size=s.shape)
d[:,:] = npr.randint(10, size=d.shape)

I, J = np.nonzero(s)
C[I, J] += d[I]

然后我分析了我制作的程序,该程序在我的机器上运行不到450毫秒(最后两行不到300毫秒)。请注意,对“ randint”的调用只是用于设置数组值,因此这些行不适用于您的用例。