Я работаю над выполнением простых линейных алгебраических манипуляций с NumPy. Все было действительно здорово до сих пор, когда я беру простые матрицы 2x2, собственные значения и векторы которых я знаю, и проверяю их на numpe.

Например, приведенная ниже примерная матрица содержит одно собственное значение e = 1 и один связанный собственный вектор [-3, 1]:

A = np.array([[-2, -9],
              [ 1,  4]])


vals, vects = np.linalg.eig(A)
vals2, vects2 = np.linalg.eigh(A)
vals3 = np.linalg.eigvals(A)

print("Eigenvalues (linalg.eig): \n", vals)
print("Eigenvalues (linalg.eigvals): \n", vals3)
print("Eigenvectors: \n", vects)

Результаты в следующем:

Eigenvalues (linalg.eig):
 [1.+1.89953279e-08j 1.-1.89953279e-08j]

Eigenvalues (linalg.eigvals):
  [1.+1.89953279e-08j 1.-1.89953279e-08j]

Eigenvectors:
 [[ 0.9486833 +0.00000000e+00j  0.9486833 -0.00000000e+00j]
 [-0.31622777-2.00228337e-09j -0.31622777+2.00228337e-09j]] 

Я понимаю, что собственные векторы в формате столбца. Если вы пренебрегаете маленькими мнимыми частями, оба вектора являются ПОЧТИ скалярными кратными единственного правильного собственного вектора.

Моя матрица не является симметричной или сопряженной симметричной, и поэтому linalg.eigh не должен работать, но я все равно попробовал. Это дает мне реальные ценности, но они полностью поддельные.

Я также искал другие подобные вопросы, и не нашел удовлетворительных ответов. Самый близкий из приведенных мною ответов - это один из ответов, в котором предлагается написать функцию для удаления собственных значений их маленьких мнимых частей. Это работает, но все еще оставляет неправильные собственные векторы.

Что здесь происходит? Как я могу это просто исправить? Кажется, немного сложнее написать свои собственные функции, чтобы исправить такую хорошо зарекомендовавшую себя библиотеку, чтобы сделать правильные простые вычисления.

2
rocksNwaves 23 Фев 2020 в 22:28

2 ответа

Лучший ответ

Numpy возвращает нормализованный собственный вектор для каждого собственного значения; поскольку собственное значение здесь имеет кратность 2, оно возвращает один и тот же собственный вектор дважды. Вы можете использовать np.real_if_close для преобразования в реальное:

In [156]: A = np.array([[-2, -9],
     ...:               [ 1,  4]])
     ...: 
     ...: w, v = np.linalg.eig(A)
     ...: v = np.real_if_close(v, tol=1)
     ...: v
Out[156]: 
array([[ 0.9486833 ,  0.9486833 ],
       [-0.31622777, -0.31622777]])

Санитарная проверка:

In [157]: v * 10**.5
Out[157]: 
array([[ 3.,  3.],
       [-1., -1.]])

Если вам нужны точные решения, а не подверженные машинным ошибкам, могу ли я предложить sympy:

In [159]: from sympy import Matrix
     ...: m = Matrix(A)
     ...: m.eigenvects()
Out[159]: 
[(1,
  2,
  [Matrix([
   [-3],
   [ 1]])])]

Где мы получаем собственное значение 1, его кратность 2 и собственный вектор, связанный с ним.

1
salt-die 23 Фев 2020 в 20:21

Здесь вы заметили относительную ошибку аппроксимации.

Numpy не точно вычисляет собственные значения и собственные векторы, а использует мощные и оптимизированные численные алгоритмы, которые дают не точные ответы, а довольно близкие. Для этих целей используется старая библиотека LAPACK dggev: http: / /www.netlib.org/lapack/double/dggev.f

Если вы ищете точный ответ, то Numpy не является решением для вас. Вместо этого взгляните на Sympy. Подобная проблема также обсуждается здесь: как вычисляются собственные числа и собственные векторы

1
Richard Nemeth 23 Фев 2020 в 20:23