考虑我有以下形式的2D阵列
D = [
[A11,A21,A31,A22,A23,A33],
[B11,B21,B31,B22,B23,B33],
[C11,C21,C31,C22,C23,C33]
]
其中每个D[i]
是对称矩阵的表示。
对称矩阵可以重塑为
[
[[A11,A21,A31
A21,A22,A23
A31,A23,A33]],
[[B11,B21,B31
B21,B22,B23
B31,B23,B33]],
[[C11,C21,C31
C21,C22,C23
C31,C23,C33]]
]
所以D[i]
是第i个对称矩阵的下三角部分(带有对角线)的值的列表
以result = np.zeros(3,3,3)
开头执行迭代循环,然后填充条目很容易。
请注意,由于已经给出了协方差矩阵的值,因此我不需要计算相关性等。我只想将2D重塑为具有一定约束(对称和正确索引)的3D
我想知道是否有更有效的方法而不使用循环?谢谢
答案 0 :(得分:1)
您可以通过3个步骤(为简单起见,从一个对称矩阵开始)实现这一目标:
假设有一个向量d0 = D [0]
d0 = D[0] # [A11,A21,A31,A22,A23,A33]
首先创建一个空矩阵
r = np.zeros([3, 3]) # note: any size will do
将d0分配到矩阵的上部
upper_tri = ~np.tri(3, 3, -1, dtype=bool)
# [[ True, True, True],
# [False, True, True],
# [False, False, True]]
r[upper_tri] = d0
# [[A11,A21,A31],
# [ 0 ,A22,A23],
# [ 0 , 0 ,A33]]
然后转置结果并将其分配给自身,但应用仅与下部三角形匹配的蒙版:
lower_tri = ~upper_tri
r[lower_tri] = r.T[lower_tri]
# [[A11,A21,A31
# A21,A22,A23
# A31,A23,A33]]
您可以使用广播来扩展此方法,但这非常棘手。您需要转置每个输入和输出矩阵。这是因为适用于标量的方法(例如A21在这里是单个标量)也将适用于向量
d0 = D.T # [ [A11, B11, C11], [A21, B21, C21], [A31, B31, C31]... ]
N = 3 # as batch size to avoid confusion
r = np.zeros([3, 3, N])
upper_tri = ~np.tri(3, 3, -1, dtype=bool) # same as before
r[upper_tri] = d0
lower_tri = ~upper_tri
r[lower_tri] = r.transpose([1, 0, 2])[lower_tri]
r = r.transpose([2, 0, 1])
答案 1 :(得分:0)
如果我理解正确,前一段时间我实际上也遇到了类似的问题。我看到了您的问题,并决定进一步解决这个问题,但提出了一般解决方案(对于3或更大的尺寸很有用)。我找不到没有 any 循环的方法(抱歉),但是它非常简单,可以定义为以数组和维度为参数的函数
解决方案 这是我用来从数组中生成所需类型的矩阵的代码(请注意,我只是删除了字母,并使用int进行演示)。它仍然使用嵌套循环。
import numpy as np
D = [
[11,21,31,22,23,33],
[11,21,31,22,23,33],
[11,21,31,22,23,33]
]
d = 3 # dimension
N = 3 # number of sets (A, B, C) or len(D)
# index offset matrix to index from D
offsets = np.zeros((d, d), dtype=int)
# adjustments to offset matrix at each i,j index
adj = np.arange(d-2, 0, -1)
for i in range(1, d-1):
offsets[i:, i:] += adj[i-1]
cov = np.empty((N, d, d), dtype=int)
# iterate over A, B, C
for n in range(N):
for i in range(d):
for j in range(d):
cov[n, i, j] = D[n][i+j+offsets[i, j]]
print(cov)
此打印
[[[11 21 31]
[21 22 23]
[31 23 33]]
[[11 21 31]
[21 22 23]
[31 23 33]]
[[11 21 31]
[21 22 23]
[31 23 33]]]
如果您有更大的组合:
D = [
[11, 21, 31, 41, 51, 61, 22, 23, 24, 25, 26, 33, 34, 35, 36, 44, 45, 46, 55, 56, 66],
[11, 21, 31, 41, 51, 61, 22, 23, 24, 25, 26, 33, 34, 35, 36, 44, 45, 46, 55, 56, 66],
[11, 21, 31, 41, 51, 61, 22, 23, 24, 25, 26, 33, 34, 35, 36, 44, 45, 46, 55, 56, 66]
]
d = 6
N = 3
offsets = np.zeros((d, d), dtype=int)
adj = np.arange(d-2, 0, -1)
for i in range(1, d-1):
offsets[i:, i:] += adj[i-1]
cov = np.empty((N, d, d), dtype=int)
for n in range(N):
for i in range(d):
for j in range(d):
cov[n, i, j] = D[n][i+j+offsets[i, j]]
print(cov)
您得到:
[[[11 21 31 41 51 61]
[21 22 23 24 25 26]
[31 23 33 34 35 36]
[41 24 34 44 45 46]
[51 25 35 45 55 56]
[61 26 36 46 56 66]]
[[11 21 31 41 51 61]
[21 22 23 24 25 26]
[31 23 33 34 35 36]
[41 24 34 44 45 46]
[51 25 35 45 55 56]
[61 26 36 46 56 66]]
[[11 21 31 41 51 61]
[21 22 23 24 25 26]
[31 23 33 34 35 36]
[41 24 34 44 45 46]
[51 25 35 45 55 56]
[61 26 36 46 56 66]]]
注释 这要求您的输入数组D遵循模式
A11, A12, A13, A14, A22, A23, A24, A33, A34, A44
与您的3D问题一样。
我找到了这种解决方案,方法是将D的索引映射到所需的矩阵上,发现它们是矩阵索引加上一些子矩阵的偏移量:
# [[i+j, i+j, i+j, i+j, i+j ],
# [i+j, i+j+3, i+j+3, i+j+3, i+j+3],
# [i+j, i+j+3, i+j+5, i+j+5, i+j+5],
# [i+j, i+j+3, i+j+5, i+j+6, i+j+6],
# [i+j, i+j+3, i+j+5, i+j+6, i+j+6]]
这些偏移量从0开始,然后随着i,j的增加,它们依次增加3,然后2,然后是1。此模式随着尺寸的增大而缩放。
答案很长,但我希望它能对您有所帮助,我以前肯定已经看过并遇到过这个问题。
欢呼