Самый быстрый способ вычислить k наибольших собственных значений и соответствующих собственных векторов с numpy

Я имею большую плотную симметричную матрицу NxN и хочу, чтобы собственные векторы соответствовали k наибольшим собственным значениям. Какой лучший способ их найти (желательно, используя numpy, но, возможно, вообще используя blas/atlas/lapack, если это единственный способ пойти)? В общем случае N намного больше, чем k (например, N > 5000, k < 10).

У Numpy есть только функции для нахождения k наибольших собственных значений, если моя стартовая матрица разрежена.

Ответы

Ответ 1

В SciPy вы можете использовать функцию linalg.eigh с параметром eigvals.

eigvals: tuple (lo, hi) Индексы наименьшего и наибольшего (в по возрастанию) собственные значения и соответствующие собственные векторы return: 0 <= lo < hi <= M-1. Если опустить, все собственные значения и возвращаются собственные векторы.

Что в вашем случае должно быть установлено (N-k,N-1).

Ответ 2

На самом деле разреженные подпрограммы работают и для плотных массивов numpy, я думаю, они используют некоторые типа итерации подпространства Крылова, поэтому им нужно вычислить несколько матричных векторов продуктов, что означает, что если ваш k < N, разреженные процедуры могут быть (незначительно?) быстрее.

Проверьте документы http://docs.scipy.org/doc/scipy/reference/tutorial/arpack.html

и следующий код (пойдите, чтобы взять хороший кофе с друзьями до его окончания)

import numpy as np
from time import clock
from scipy.linalg import eigh as largest_eigh
from scipy.sparse.linalg.eigen.arpack import eigsh as largest_eigsh

np.set_printoptions(suppress=True)
np.random.seed(0)
N=5000
k=10
X = np.random.random((N,N)) - 0.5
X = np.dot(X, X.T) #create a symmetric matrix

# Benchmark the dense routine
start = clock()
evals_large, evecs_large = largest_eigh(X, eigvals=(N-k,N-1))
elapsed = (clock() - start)
print "eigh elapsed time: ", elapsed

# Benchmark the sparse routine
start = clock()
evals_large_sparse, evecs_large_sparse = largest_eigsh(X, k, which='LM')
elapsed = (clock() - start)
print "eigsh elapsed time: ", elapsed