将矩阵列转换为对角矩阵并在没有 for 循环的情况下将它们包装起来

Transform matrix columns into diagonal matrices and wrap them up without for loops

我有 M 个向量,每个向量有 N 个条目(MxN 矩阵,如果你愿意的话):

A = [A1, A2, ... , AN]
B = [B1, B2, ... , BN]
...
Z = [Z1, Z2, ... , ZN]

我想转换这些以便输出为:

[[[A1,  0, ... ,  0],
  [0,  B1, ... ,  0],
   ...
  [0,   0, ... , Z1]],
  
 [[A2,  0, ... ,  0],
  [0,  B2, ... ,  0],
   ...
  [0,   0, ... , Z2]],
  
  ...
  
 [[AN,  0, ... ,  0],
  [0,  BN, ... ,  0],
   ...
  [0,   0, ... , ZN]]]

目标是 完全使用 for 循环并仅通过 numpy 操作来实现。想法?

您可以使用 diag numpy 函数,例如

import numpy as np

A = [0, 1, 2]
B = [0, 1, 2]
C = [0, 1, 2]

# Merge lists into matrix
X = np.array([A, B, C])

# Index columns and merge into list of diagonal matrices
print([np.diag(X[:, 0]), np.diag(X[:, 1]), np.diag(X[:, 2])])

要使最后一步(以上)自动化,您可能需要使用 for 循环,例如

diag_list = []
for n in N:
   diag_list.append(np.diag(X[:, n])

我发现了一个示例 here,它使用 np.apply_along_axis 填充多个对角线。


A = [11, 12, 13, 14]
B = [21, 22, 23, 24]
C = [31, 32, 33, 34]
D = [41, 42, 43, 44]
E = [51, 52, 53, 54]

Z = np.array([A, B, C, D, E])

构建 Z 后,您对其进行转置并用其值填充一个空的对角线数组:

>>> np.apply_along_axis(np.diag, -1, Z.T)
array([[[11,  0,  0,  0,  0],
        [ 0, 21,  0,  0,  0],
        [ 0,  0, 31,  0,  0],
        [ 0,  0,  0, 41,  0],
        [ 0,  0,  0,  0, 51]],

       [[12,  0,  0,  0,  0],
        [ 0, 22,  0,  0,  0],
        [ 0,  0, 32,  0,  0],
        [ 0,  0,  0, 42,  0],
        [ 0,  0,  0,  0, 52]],

       [[13,  0,  0,  0,  0],
        [ 0, 23,  0,  0,  0],
        [ 0,  0, 33,  0,  0],
        [ 0,  0,  0, 43,  0],
        [ 0,  0,  0,  0, 53]],

       [[14,  0,  0,  0,  0],
        [ 0, 24,  0,  0,  0],
        [ 0,  0, 34,  0,  0],
        [ 0,  0,  0, 44,  0],
        [ 0,  0,  0,  0, 54]]])

虽然您的问题很清楚,但我们更愿意看到 [MCVE](该标签在评论中展开,请参阅 SO 介绍)。当要求无循环解决方案时,礼貌地展示一个有效的循环解决方案 - 这为我们提供了一些测试依据。我至少想证明我的答案有效。

所以这是我的最小工作示例 - 带有循环解决方案:

In [308]: M = np.stack([np.arange(i,j) for i,j in zip([1,11,21],[5,15,25])])
In [309]: M.shape
Out[309]: (3, 4)
In [310]: M
Out[310]: 
array([[ 1,  2,  3,  4],
       [11, 12, 13, 14],
       [21, 22, 23, 24]])
In [311]: np.stack([np.diag(M[:,i]) for i in range(4)])
Out[311]: 
array([[[ 1,  0,  0],
        [ 0, 11,  0],
        [ 0,  0, 21]],

       [[ 2,  0,  0],
        [ 0, 12,  0],
        [ 0,  0, 22]],

       [[ 3,  0,  0],
        [ 0, 13,  0],
        [ 0,  0, 23]],

       [[ 4,  0,  0],
        [ 0, 14,  0],
        [ 0,  0, 24]]])

np.diagonal 让我们指定坐标轴。因此,例如我们可以使用它从 Out[311]:

中提取起始数组
In [318]: np.diagonal(Out[311],axis1=1, axis2=2)
Out[318]: 
array([[ 1, 11, 21],
       [ 2, 12, 22],
       [ 3, 13, 23],
       [ 4, 14, 24]])

我没有(副手)看到多维建筑。我们可以深入研究文档,或者查看现有代码来构建等效代码。或者只是接受该循环的时间惩罚:)

diag(onal) 函数使用 flat 索引提高速度,但使用多维索引更容易。我们可以使用

访问这些相同的值
In [319]: Out[311][:,np.arange(3),np.arange(3)]
Out[319]: 
array([[ 1, 11, 21],
       [ 2, 12, 22],
       [ 3, 13, 23],
       [ 4, 14, 24]])

我们可以使用相同的索引来赋值。

In [320]: res = np.zeros((4,3,3),int)
In [321]: res[:,np.arange(3), np.arange(3)] = M.T
In [322]: res
Out[322]: 
array([[[ 1,  0,  0],
        [ 0, 11,  0],
        [ 0,  0, 21]],

       [[ 2,  0,  0],
        [ 0, 12,  0],
        [ 0,  0, 22]],

       [[ 3,  0,  0],
        [ 0, 13,  0],
        [ 0,  0, 23]],

       [[ 4,  0,  0],
        [ 0, 14,  0],
        [ 0,  0, 24]]])

如果最后这些步骤令人困惑,我建议您尝试创建自己的二维对角线阵列。从小处着手,并以此知识为基础。