Почему мой расчет SVD отличается от расчета SVD этой матрицы numpy? - PullRequest
0 голосов
/ 24 сентября 2018

Я пытаюсь вручную вычислить SVD матрицы A, определенной ниже, но у меня возникли некоторые проблемы.Вычисление его вручную и с помощью метода svd в numpy дает два разных результата.

Ниже вычисляется вручную:

import numpy as np
A = np.array([[3,2,2], [2,3,-2]])
V = np.linalg.eig(A.T @ A)[1]
U = np.linalg.eig(A @ A.T)[1]
S = np.c_[np.diag(np.sqrt(np.linalg.eig(A @ A.T)[0])), [0,0]]
print(A)
print(U @ S @ V.T)

И вычисляется с помощью метода svd numpy:

X,Y,Z = np.linalg.svd(A)
Y = np.c_[np.diag(Y), [0,0]]
print(A)
print(X @ Y @ Z)

Когда выполняются эти два кода.Ручной расчет не равен методу SVD.Почему существует несоответствие между этими двумя расчетами?

1 Ответ

0 голосов
/ 25 сентября 2018

Посмотрите на собственные значения, возвращаемые np.linalg.eig(A.T @ A):

In [57]: evals, evecs = np.linalg.eig(A.T @ A)

In [58]: evals
Out[58]: array([2.50000000e+01, 3.61082692e-15, 9.00000000e+00])

Итак (игнорируя обычную неточность с плавающей запятой), он вычислил [25, 0, 9].Собственные векторы, связанные с этими собственными значениями, находятся в столбцах evecs в том же порядке.Но ваша конструкция S не соответствует этому порядку;вот ваш S:

In [60]: S
Out[60]: 
array([[5., 0., 0.],
       [0., 3., 0.]])

Когда вы вычисляете U @ S @ V.T, значения в S @ V.T не выровнены правильно.

Для быстрого исправления вы можете перезапустить свой код с помощьюS установить явно следующим образом:

S = np.array([[5, 0, 0],
              [0, 0, 3]])

С этим изменением ваш код выдаст

[[ 3  2  2]
 [ 2  3 -2]]
[[-3. -2. -2.]
 [-2. -3.  2.]]

Это лучше, но почему знаки неправильные?Теперь проблема в том, что вы независимо вычислили U и V.Собственные векторы не уникальны;они являются основой собственного пространства, и такая основа не уникальна.Если собственное значение простое, и если вектор нормализован, чтобы иметь длину один (что делает numpy.linalg.eig), все еще есть выбор знака, который будет сделан.То есть, если v является собственным вектором, то и -v.Выбор, сделанный eig при вычислении U и V, не обязательно приведет к восстановлению знака A при вычислении U @ S @ V.T.

Оказывается, вы можете получитьрезультат, который вы ожидаете, просто поменяв местами все знаки в U или V.Вот модифицированная версия вашего скрипта, которая генерирует ожидаемый вывод:

import numpy as np

A = np.array([[3,  2,  2],
              [2,  3, -2]])

U = np.linalg.eig(A @ A.T)[1]
V = -np.linalg.eig(A.T @ A)[1]
#S = np.c_[np.diag(np.sqrt(np.linalg.eig(A @ A.T)[0])), [0,0]]
S = np.array([[5, 0, 0],
              [0, 0, 3]])

print(A)
print(U @ S @ V.T)

Вывод:

[[ 3  2  2]
 [ 2  3 -2]]
[[ 3.  2.  2.]
 [ 2.  3. -2.]]
...