Разница между разложением матрицы Ruby по собственным значениям и Numpy

#ruby #numpy #matrix #eigenvalue #eigenvector

#ruby #numpy #матрица #собственное значение #собственный вектор

Вопрос:

Я пытаюсь использовать класс Ruby (2.5.1) Matrix для вычисления разложения по сингулярным значениям. При создании кода я обнаружил разницу между результатами Python Numpy SVD и соответствующим матричным подходом Ruby. Базовый подход заключается в следующем:

  • A: Матрица, подлежащая обработке
  • X: A * В матрице A, умноженной на транспонированную матрицу A.
  • Y: В * Матрица A, транспонированная, умноженная на матрицу A

с помощью этого:

  • U состоит из столбцов собственных векторов X
  • S — диагональная матрица собственных значений квадратного корня, упорядоченных по размеру
  • V состоит из собственных векторов строк Y

Следующее матричное произведение снова создает матрицу A:

  • A = USVT

Сравнивая класс 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(amp;:inspect)
puts 'Matrix V'
vt = Matrix[*v_ev]
puts vt.to_a.map(amp;:inspect)
puts 'Eigenvalues S'
p sqrt_diagonal_values = v.eigenvalues().map {|value| Math.sqrt(value)}.reverse
  

Результаты кода Numpy следующие (пример первой строки U)

Матрица U

-7.40847968e-01 -1.08616810e-01 1.98359970e-01 5.12144302e-01 -3.71090574e-01

Собственный вектор s

2.32131207 1.47894683 0.65132674

Матрица VT

-0.50752384 -0.6681011 -0.54411439

-0.85772795 0.45183049 0.24525898

-0.08198967 -0.59117691 0.80236373

Код собственной системы Ruby Matrix выдает следующие результаты:

Матрица U (первая строка)

[0.7408479676229094, -0.1086168097636038, -0.1983599695144702, -0.5690831468812522, -0.27594269683347544]

Собственный вектор s

[2.3213120745694042, 1.478946829710326, 0.6513267439220222]

Матрица VT

[0.5075238412366166, 0.6681010991839039, 0.544114392242743]

[-0.8577279545170795, 0.4518304852203834, 0.2452589828435646]

[-0.08198967383992087, -0.5911769057522231, 0.8023637326604754]

Разница между отрицательным и положительным значениями основана на вычислении собственных значений и не влияет на общий результат. Учитываются абсолютные значения.

Когда вы смотрите на результат матрицы U кода Ruby, он начинает отличаться от кода Numpy, начиная со столбца 4

Сигма- и V-матрицы в порядке.

В качестве теста вы также можете запустить этот код со следующей матрицей

 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