是否有一种矢量化方法来反转 n x m numpy 数组并将前端零移到后面

Is there a vectorized approach to reverse an n x m numpy array and shift the front end zeros to the back

假设

A = np.array([1,0,2,0,0,0,0],[1,2,0,3,5,0,0],[5,6,7,0,9,5,10]) 

从 A 我试图创建 B 这样:

B = np.array([2,0,1,0,0,0,0],[5,3,0,2,1,0,0],[10,5,9,0,7,6,5])

换句话说,B 是 A 的反转,前导零旋转到后面。是否有矢量化方法来实现此目的?

(创建 B 以便我可以 vectorize the summation of the integer values in A with their reflection across the zero off diagonal)例如A[1][0]+A[1][4], A[1][1]+A[1][3] = (B+A)[0:2]

我唯一想到的就是尝试这样的事情。

首先我把A反了

B = A.copy()
B = B[...,::-1]

产生

B
Out[185]: 
array([[ 0,  0,  0,  0,  2,  0,  1],
       [ 0,  0,  5,  3,  0,  2,  1],
       [10,  5,  9,  0,  7,  6,  5]])

然后我用以下内容遍历每一行。

for i in range(0,B.shape[0]):
    a=np.trim_zeros(B[i])
    B[i]=np.pad(a,(0,B.shape[1]-a.shape[0])

B
Out[]: 
array([[ 2,  0,  1,  0,  0,  0,  0],
       [ 5,  3,  0,  2,  1,  0,  0],
       [10,  5,  9,  0,  7,  6,  5]])

但实际数据集的行和列可能大几个数量级。这个问题有没有向量化的解决方案。

这是一个带有掩码的矢量化的 -

# nonzeros mask
nnz = A!=0

# Mask surrounded by nonzeros
max_accum = np.maximum.accumulate
island = max_accum(nnz,axis=1) & max_accum(nnz[:,::-1],axis=1)[:,::-1]

# Setup o/p array. Extract flipped A elements within each island per row and 
# assign into sorted mask i.e. brought to front mask places in o/p
out = np.zeros_like(A)
out[np.sort(island, axis=1)[:,::-1]] = A[:,::-1][island[:,::-1]]

说明

输入数组(用于 ref 和一个不同的数组来处理极端情况并更好地解释):

In [147]: A
Out[147]: 
array([[ 1,  0,  2,  0,  0,  0,  0],
       [ 0,  0,  0,  2,  4,  0,  6],
       [ 5,  6,  7,  0,  9,  5, 10]])

nonzeros-surrounded岛掩码:

前向累积掩码

In [148]: max_accum(nnz,axis=1)
Out[148]: 
array([[ True,  True,  True,  True,  True,  True,  True],
       [False, False, False,  True,  True,  True,  True],
       [ True,  True,  True,  True,  True,  True,  True]])

带翻转nnz掩码的后向累积掩码,执行正向累积,向后翻转

In [149]: max_accum(nnz[:,::-1],axis=1)[:,::-1]
Out[149]: 
array([[ True,  True,  True, False, False, False, False],
       [ True,  True,  True,  True,  True,  True,  True],
       [ True,  True,  True,  True,  True,  True,  True]])

最终组合面具给我们岛

In [150]: max_accum(nnz,axis=1) & max_accum(nnz[:,::-1],axis=1)[:,::-1]
Out[150]: 
array([[ True,  True,  True, False, False, False, False],
       [False, False, False,  True,  True,  True,  True],
       [ True,  True,  True,  True,  True,  True,  True]])

选择与赋值:

In [159]: A
Out[159]: 
array([[ 1,  0,  2,  0,  0,  0,  0],
       [ 0,  0,  0,  2,  4,  0,  6],
       [ 5,  6,  7,  0,  9,  5, 10]])

In [160]: island
Out[160]: 
array([[ True,  True,  True, False, False, False, False],
       [False, False, False,  True,  True,  True,  True],
       [ True,  True,  True,  True,  True,  True,  True]])

In [161]: A[:,::-1]
Out[161]: 
array([[ 0,  0,  0,  0,  2,  0,  1],
       [ 6,  0,  4,  2,  0,  0,  0],
       [10,  5,  9,  0,  7,  6,  5]])

In [162]: island[:,::-1]
Out[162]: 
array([[False, False, False, False,  True,  True,  True],
       [ True,  True,  True,  True, False, False, False],
       [ True,  True,  True,  True,  True,  True,  True]])

因此,select :

In [165]: A[:,::-1][island[:,::-1]]
Out[165]: array([ 2,  0,  1,  6,  0,  4,  2, 10,  5,  9,  0,  7,  6,  5])

到selectbrought-to-frontmask,排序island mask,其中selectso/p处要赋值到:

In [163]: np.sort(island, axis=1)[:,::-1]
Out[163]: 
array([[ True,  True,  True, False, False, False, False],
       [ True,  True,  True,  True, False, False, False],
       [ True,  True,  True,  True,  True,  True,  True]])

然后,将那些 A selected 分配给带有排序掩码的输出:

In [166]: out
Out[166]: 
array([[ 2,  0,  1,  0,  0,  0,  0],
       [ 6,  0,  4,  2,  0,  0,  0],
       [10,  5,  9,  0,  7,  6,  5]])