Я пытаюсь использовать матричный класс Ruby (2.5.1) для вычисления разложения по сингулярным значениям.При создании кода я обнаружил разницу между результатами Python Numpy SVD и соответствующим подходом Ruby Matrix.Базовый подход заключается в следующем:
- A: Матрица, подлежащая обработке
- X: A * AT Матрица A, умноженная на матрицу A, транспонированную
- Y: AT *Матрица А, транспонированная, умноженная на Матрицу А
с этим:
- U состоит из столбцов собственных векторов X
- S - диагональматрица собственных значений квадратного корня, упорядоченных по размеру
- V, состоит из собственных векторов строки Y
Следующий матричный продукт снова производит матрицу A:
Сравнение класса Ruby Matrix и Numpy дает те же результаты, вплоть до n от U <4. Но как только n> 4 в пределах U результаты столбцов 4 и выше начинают отличаться от результатов Numpy.Теперь я задаюсь вопросом, делаю ли я что-то не так здесь или есть проблема с классом Matrix в целом.
Для Numpy я использовал следующий код
# Calculate and reconstruct SVD
from numpy import array
from numpy import diag
from numpy import dot
from numpy import zeros
from scipy.linalg import svd
# define a matrix
A = array([[1,1,1], [0,1,1], [1,0,0], [0,1,0], [1,0,0]])
print(A)
# Singular-value decomposition
U, s, VT = svd(A)
print('Matrix U')
print(U)
print('Eigenvektor')
print(s)
print('Matrix VT')
print(VT)
# create m x n Sigma matrix
Sigma = zeros((A.shape[0], A.shape[1]))
# populate Sigma with n x n diagonal matrix
Sigma[:A.shape[1], :A.shape[1]] = diag(s)
# reconstruct matrix
B = U.dot(Sigma.dot(VT))
print(B)
ДляВ вычислениях Ruby я использовал следующий код:
require 'matrix'
a = Matrix[ [1,1,1], [0,1,1], [1,0,0], [0,1,0], [1,0,0]]
x = a * a.transpose
y = a.transpose * a
u = Matrix::EigenvalueDecomposition.new(x)
u_ev = u.eigenvector_matrix().to_a
v = Matrix::EigenvalueDecomposition.new(y)
v_ev = v.eigenvector_matrix().transpose.to_a
u_ev.map! {|row| row.reverse}
v_ev.reverse!
puts 'Matrix U'
u = Matrix[*u_ev]
puts u.to_a.map(&:inspect)
puts 'Matrix V'
vt = Matrix[*v_ev]
puts vt.to_a.map(&:inspect)
puts 'Eigenvalues S'
p sqrt_diagonal_values = v.eigenvalues().map {|value| Math.sqrt(value)}.reverse
Результаты кода Numpy (пример первой строки U)
Matrix U
-7.40847968e-01 -1.08616810e-01 1.98359970e-01 5.12144302e-01 -3.71090574e-01
...
Собственный вектор с
2.32131207 1.47894683 0.65132674
Матрица VT
-0,50752384 -0,6681011 -0,54411439
-0,85772795 0,45183049 0,24525898
-0,08198967 -0,59117691 0,802,237373
* матрица Ригса *1055* 1056следующие результаты:
Матрица U (первый ряд)
[0,7408479676229094, -0,1086168097636038, -0,1983599695144702, -0,5690831468812522, -0,27594269683347544]
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 10 * 10 ** Eigenvector s
[2.3213120745694042, 1.478946829710326, 0,6513267439220222]
1068 * Матрица VT 1070 * [+0,5075238412366166, +0,6681010991839039, +0,544114392242743] 1072 * [- +0,8577279545170795, +0,4518304852203834, +0,2452589828435646] 1074 * [- +0,08198967383992087, -0,5911769057522231,0.8023637326604754]
Разница между отрицательными и положительными значениями основана на вычислении собственных значений и не влияет на общий результат.Счетчик абсолютных значений.
Когда вы смотрите на результат матрицы U кода Ruby, он начинает отличаться от кода Numpy, начиная со столбца 4 +
. Сигма и матрица Vok.
В качестве теста вы также можете запустить этот код со следующей матрицей
A = array([[4,-5,-1],[7,-2,3],[-1,4,-3],[8,2,6]]) #for Python
a = Matrix[[4,-5,-1],[7,-2,3],[-1,4,-3],[8,2,6]] #for Ruby
В этом случае оба результата одинаковы.И когда вы проверяете A = USVT, результаты снова дают исходную матрицу A.Таким образом, общая система оказалась работоспособной.
У кого-нибудь была идея, почему результаты отличаются?
Любая помощь приветствуется
Krid