两个numpy数组中所有行的组合

Ian*_*des 5 python arrays numpy

我有两个阵列,例如有形状(3,2),另一个有形状(10,7).我想要两个数组的所有组合,这样我最终得到一个9列数组.换句话说,我希望第一个数组的每一行的所有组合与第二个数组的行.

我怎样才能做到这一点?据我所知,我没有正确使用meshgrid.

根据以前的帖子,我的印象是

a1 = np.zeros((10,7))
a2 = np.zeros((3,2))
r = np.array(np.meshgrid(a1, a2)).T.reshape(-1, a1.shape[1] + a2.shape[1])
Run Code Online (Sandbox Code Playgroud)

会工作,但这给我的尺寸(84,10).

Div*_*kar 5

方法#1

专注于性能,这是一种用于作业array-initializationelement-broadcasting用于作业的方法 -

m1,n1 = a1.shape
m2,n2 = a2.shape
out = np.zeros((m1,m2,n1+n2),dtype=int)
out[:,:,:n1] = a1[:,None,:]
out[:,:,n1:] = a2
out.shape = (m1*m2,-1)
Run Code Online (Sandbox Code Playgroud)

解释 :

诀窍在于两个步骤:

out[:,:,:n1] = a1[:,None,:]
out[:,:,n1:] = a2
Run Code Online (Sandbox Code Playgroud)

第1步 :

In [227]: np.random.seed(0)

In [228]: a1 = np.random.randint(1,9,(3,2))

In [229]: a2 = np.random.randint(1,9,(2,7))

In [230]: m1,n1 = a1.shape
     ...: m2,n2 = a2.shape
     ...: out = np.zeros((m1,m2,n1+n2),dtype=int)
     ...: 

In [231]: out[:,:,:n1] = a1[:,None,:]

In [232]: out[:,:,:n1]
Out[232]: 
array([[[5, 8],
        [5, 8]],

       [[6, 1],
        [6, 1]],

       [[4, 4],
        [4, 4]]])

In [233]: a1[:,None,:]
Out[233]: 
array([[[5, 8]],

       [[6, 1]],

       [[4, 4]]])
Run Code Online (Sandbox Code Playgroud)

因此,基本上我们正在分配a1保持第一个轴与相应输出轴对齐的元素,同时让沿输出数组的第二个轴的元素以广播方式填充,对应newaxisa1沿该轴添加的元素。这是这里的症结所在并带来性能,因为我们没有分配额外的内存空间,否则我们将需要使用显式重复/平铺方法。

第2步 :

In [237]: out[:,:,n1:] = a2

In [238]: out[:,:,n1:]
Out[238]: 
array([[[4, 8, 2, 4, 6, 3, 5],
        [8, 7, 1, 1, 5, 3, 2]],

       [[4, 8, 2, 4, 6, 3, 5],
        [8, 7, 1, 1, 5, 3, 2]],

       [[4, 8, 2, 4, 6, 3, 5],
        [8, 7, 1, 1, 5, 3, 2]]])

In [239]: a2
Out[239]: 
array([[4, 8, 2, 4, 6, 3, 5],
       [8, 7, 1, 1, 5, 3, 2]])
Run Code Online (Sandbox Code Playgroud)

在这里,我们基本上是 沿着输出数组的第一个轴广播该 a2,而没有明确地进行重复复制。

样本输入,输出完整性 -

In [242]: a1
Out[242]: 
array([[5, 8],
       [6, 1],
       [4, 4]])

In [243]: a2
Out[243]: 
array([[4, 8, 2, 4, 6, 3, 5],
       [8, 7, 1, 1, 5, 3, 2]])

In [244]: out
Out[244]: 
array([[[5, 8, 4, 8, 2, 4, 6, 3, 5],
        [5, 8, 8, 7, 1, 1, 5, 3, 2]],

       [[6, 1, 4, 8, 2, 4, 6, 3, 5],
        [6, 1, 8, 7, 1, 1, 5, 3, 2]],

       [[4, 4, 4, 8, 2, 4, 6, 3, 5],
        [4, 4, 8, 7, 1, 1, 5, 3, 2]]])
Run Code Online (Sandbox Code Playgroud)

方法#2

另一个与tiling/repeating-

parte1 = np.repeat(a1[:,None,:],m2,axis=0).reshape(-1,m2)
parte2 = np.repeat(a2[None],m1,axis=0).reshape(-1,n2)
out = np.c_[parte1, parte2] 
Run Code Online (Sandbox Code Playgroud)

  • @Chiel 尽力解释。希望这对读者有所帮助。 (2认同)