Посмотрите на собственные значения, возвращаемые 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.]]