如何使用数组的光谱分量来变换数组

问题描述 投票:0回答:2

我正在尝试使用其光谱分量来转换数组。

让我们考虑这个 4x4 数组

import numpy as np
from numpy.linalg import eig


arr = np.asarray([[23, 34, 78, 54],
                   [87, 98, 23, 67],
                   [76, 67, 98, 29],
                   [56, 88, 28, 27]])

它的邻接矩阵是

A = np.asarray([[0., 1., 0., 0., 1., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
                   [1., 0., 1., 0., 1., 1., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
                   [0., 1., 0., 1., 0., 1., 1., 1., 0., 0., 0., 0., 0., 0., 0., 0.],
                   [0., 0., 1., 0., 0., 0., 1., 1., 0., 0., 0., 0., 0., 0., 0., 0.],
                   [1., 1., 0., 0., 0., 1., 0., 0., 1., 1., 0., 0., 0., 0., 0., 0.],
                   [1., 1., 1., 0., 1., 0., 1., 0., 1., 1., 1., 0., 0., 0., 0., 0.],
                   [0., 1., 1., 1., 0., 1., 0., 1., 0., 1., 1., 1., 0., 0., 0., 0.],
                   [0., 0., 1., 1., 0., 0., 1., 0., 0., 0., 1., 1., 0., 0., 0., 0.],
                   [0., 0., 0., 0., 1., 1., 0., 0., 0., 1., 0., 0., 1., 1., 0., 0.],
                   [0., 0., 0., 0., 1., 1., 1., 0., 1., 0., 1., 0., 1., 1., 1., 0.],
                   [0., 0., 0., 0., 0., 1., 1., 1., 0., 1., 0., 1., 0., 1., 1., 1.],
                   [0., 0., 0., 0., 0., 0., 1., 1., 0., 0., 1., 0., 0., 0., 1., 1.],
                   [0., 0., 0., 0., 0., 0., 0., 0., 1., 1., 0., 0., 0., 1., 0., 0.],
                   [0., 0., 0., 0., 0., 0., 0., 0., 1., 1., 1., 0., 1., 0., 1., 0.],
                   [0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 1., 1., 0., 1., 0., 1.],
                   [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 1., 0., 0., 1., 0.]])

它的次数和拉普拉斯矩阵:

degree = A.sum(axis=1)
D = np.diag(degree)

# Laplacian matrix
L = D - A

计算其特征向量和特征值,并按降序排序

eig_val, eig_vec = eig(L)
idx = eig_val.argsort()[::-1]

对特征向量进行相应排序

eig_vec = eig_vec[:,idx]

2 个不同特征向量的乘积必须为 0。 我注意到这里的情况并非如此,例如第一个和第二个特征向量的乘积是

sum(np.multiply(eig_vec[0], eig_vec[1])) = 0.043247527085787975

我有什么遗漏的吗?

计算输入数组的光谱分量

spectral = np.matmul(eig_vec.transpose(), arr.flatten())
print(spectral.shape)

取前 15 个成分。

masked = np.zeros(spectral.shape)
m = spectral[:15]
masked[:15] = m

获取新功能

updated_arr = np.matmul(eig_vec, masked)
updated_arr = updated_arr.reshape(4, -1)

print(updated_arr)
array([[-40.29945921, -20.838019  ,  15.23873386,  -1.31402251],
       [ 33.1372913 ,  37.06095382, -34.98050288,  16.02987125],
       [ 10.92036053,   8.63461724,  42.59316054, -34.61663745],
       [ -5.31097749,  33.28191998, -33.21174921, -26.32554079]])

更新后的数组与原始数组有很大不同。

欢迎任何建议或资源查看。

python signal-processing linear-algebra spectral
2个回答
0
投票

回答关于正交特征向量的部分: np.linalg.eig 返回特征向量,使得 eigenvectors[:,i] 列是对应于特征值 eigenvalues[i] 的特征向量。所以像这样计算乘积

sum(np.multiply(eig_vec[:,0], eig_vec[:,1]))

总和将为零。


0
投票

也许您遇到了一些数字稳定性问题。要获得对称矩阵的特征分解,您应该使用

eigh
函数而不是
eig
。以下代码对我有用:

import numpy as np
from numpy.linalg import eigh

A = np.asarray([[0., 1., 0., 0., 1., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
                   [1., 0., 1., 0., 1., 1., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
                   [0., 1., 0., 1., 0., 1., 1., 1., 0., 0., 0., 0., 0., 0., 0., 0.],
                   [0., 0., 1., 0., 0., 0., 1., 1., 0., 0., 0., 0., 0., 0., 0., 0.],
                   [1., 1., 0., 0., 0., 1., 0., 0., 1., 1., 0., 0., 0., 0., 0., 0.],
                   [1., 1., 1., 0., 1., 0., 1., 0., 1., 1., 1., 0., 0., 0., 0., 0.],
                   [0., 1., 1., 1., 0., 1., 0., 1., 0., 1., 1., 1., 0., 0., 0., 0.],
                   [0., 0., 1., 1., 0., 0., 1., 0., 0., 0., 1., 1., 0., 0., 0., 0.],
                   [0., 0., 0., 0., 1., 1., 0., 0., 0., 1., 0., 0., 1., 1., 0., 0.],
                   [0., 0., 0., 0., 1., 1., 1., 0., 1., 0., 1., 0., 1., 1., 1., 0.],
                   [0., 0., 0., 0., 0., 1., 1., 1., 0., 1., 0., 1., 0., 1., 1., 1.],
                   [0., 0., 0., 0., 0., 0., 1., 1., 0., 0., 1., 0., 0., 0., 1., 1.],
                   [0., 0., 0., 0., 0., 0., 0., 0., 1., 1., 0., 0., 0., 1., 0., 0.],
                   [0., 0., 0., 0., 0., 0., 0., 0., 1., 1., 1., 0., 1., 0., 1., 0.],
                   [0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 1., 1., 0., 1., 0., 1.],
                   [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 1., 0., 0., 1., 0.]])

degree = A.sum(axis=1)
D = np.diag(degree)

# Laplacian matrix
L = D - A

eig_val, eig_vec = eigh(L)

print(np.mean(np.abs(np.dot(np.dot(eig_vec, np.diag(eig_val)), eig_vec.transpose()) - L)))
# -> 1.5500965941594069e-15

def compare(k):
    cmp_val = eig_val[len(eig_val)-k:]
    cmp_vec = eig_vec[:, len(eig_val)-k:]
    print(np.mean(np.abs(np.dot(np.dot(cmp_vec, np.diag(cmp_val)), cmp_vec.transpose()) - L)))

compare(4)
# -> 0.4905237882047826

compare(8)
# -> 0.3885449860779778

compare(12)
# -> 0.1260071124311158

compare(14)
# -> 0.05127788166023957

compare(15)
# -> 1.5583365306702967e-15

这里是关于

eig
eigh
之间差异的进一步讨论: NumPy:linalg.eig() 和 linalg.eigh() 之间的区别.

© www.soinside.com 2019 - 2024. All rights reserved.