Python 二维数组的Numpy-einsum外和

Python 二维数组的Numpy-einsum外和,python,numpy,numpy-einsum,Python,Numpy,Numpy Einsum,我试着寻找答案,但找不到我需要的。如果这是一个重复的问题,请道歉 假设我有一个二维数组,其形状(n,n*m)。我要做的是将这个数组的外和转换成一个数组,这个数组的形状(n*m,n*m)。例如,假设我有 A = array([[1., 1., 2., 2.], [1., 1., 2., 2.]]) 我想对A和A.T进行外部求和,这样输出为: >>> array([[2., 2., 3., 3.], [2., 2., 3., 3.],

我试着寻找答案,但找不到我需要的。如果这是一个重复的问题,请道歉

假设我有一个二维数组,其形状
(n,n*m)
。我要做的是将这个数组的外和转换成一个数组,这个数组的形状
(n*m,n*m)
。例如,假设我有

A = array([[1., 1., 2., 2.],
           [1., 1., 2., 2.]])
我想对
A
A.T
进行外部求和,这样输出为:

>>> array([[2., 2., 3., 3.],
           [2., 2., 3., 3.],
           [3., 3., 4., 4.],
           [3., 3., 4., 4.]])
请注意,
np.add.outer
不起作用,因为它将输入中的数据分解为向量。我可以通过这样做来实现类似的目标

np.tile(A, (2, 1)) + np.tile(A.T, (1, 2))
但当
n
m
相当大(
n>100
m>1000
)时,这似乎不合理。是否可以使用
einsum
写入此总和?我就是搞不懂
einsum

一种方法是

(A.reshape(-1,*A.shape).T+A)[:,0,:]
我认为
n>100
m>1000
会占用大量内存

但这不就是

np.add.outer(A,A)[:,0,:].reshape(4,-1)

要利用
广播
,我们需要将其分解为
3D
,然后排列轴并添加-

n = A.shape[0]
m = A.shape[1]//n
a = A.reshape(n,m,n) # reshape to 3D
out = (a[None,:,:,:] + a.transpose(1,2,0)[:,:,None,:]).reshape(n*m,-1)
样本运行以进行验证-

In [359]: # Setup input array
     ...: np.random.seed(0)
     ...: n,m = 3,4
     ...: A = np.random.randint(1,10,(n,n*m))

In [360]: # Original soln
     ...: out0 = np.tile(A, (m, 1)) + np.tile(A.T, (1, m))

In [361]: # Posted soln
     ...: n = A.shape[0]
     ...: m = A.shape[1]//n
     ...: a = A.reshape(n,m,n)
     ...: out = (a[None,:,:,:] + a.transpose(1,2,0)[:,:,None,:]).reshape(n*m,-1)

In [362]: np.allclose(out0, out)
Out[362]: True
n
m
-

In [363]: # Setup input array
     ...: np.random.seed(0)
     ...: n,m = 100,100
     ...: A = np.random.randint(1,10,(n,n*m))

In [364]: %timeit np.tile(A, (m, 1)) + np.tile(A.T, (1, m))
1 loop, best of 3: 407 ms per loop

In [365]: %%timeit
     ...: # Posted soln
     ...: n = A.shape[0]
     ...: m = A.shape[1]//n
     ...: a = A.reshape(n,m,n)
     ...: out = (a[None,:,:,:] + a.transpose(1,2,0)[:,:,None,:]).reshape(n*m,-1)
1 loop, best of 3: 219 ms per loop
使用
numexpr进一步提升性能

我们可以利用大量数据,提高内存效率,从而提高性能-

import numexpr as ne

n = A.shape[0]
m = A.shape[1]//n
a = A.reshape(n,m,n)
p1 = a[None,:,:,:]
p2 = a.transpose(1,2,0)[:,:,None,:]
out = ne.evaluate('p1+p2').reshape(n*m,-1)
使用相同的大型
n
m
设置进行计时-

In [367]: %%timeit
     ...: # Posted soln
     ...: n = A.shape[0]
     ...: m = A.shape[1]//n
     ...: a = A.reshape(n,m,n)
     ...: p1 = a[None,:,:,:]
     ...: p2 = a.transpose(1,2,0)[:,:,None,:]
     ...: out = ne.evaluate('p1+p2').reshape(n*m,-1)
10 loops, best of 3: 152 ms per loop

einsum
实现产品的总和;它可以用于外积,但不能用于外和。使用
磁贴
可以创建两个与目标大小相同的临时数组,对吗?问题是否如此之大,以至于您只能拥有一个这样大小的数组?您是否可以通过更改
A
的第二行来进行诊断?从示例中退一步,重点关注维度<代码>A可以被重塑为(n,n,m),目标可以被重塑为(n,m,n,m)。如果我们可以创建一个和,即(n,n,m,m),我们可以转置得到正确的形状。这些价值观正确吗?