Ответ 1
Ваша реализация
Вы вычисляете собственные векторы корреляционной матрицы, то есть ковариационную матрицу нормированных переменных. data/=np.std(data, axis=0)
не является частью классического PCA, мы data/=np.std(data, axis=0)
только переменные. Таким образом, PCA sklearn не показывает масштаб данных заранее.
Кроме того, вы на правильном пути, если отвлечься от факта, что код, который вы предоставили, не запускался;). Вы только путались с макетами строк/столбцов. Честно говоря, мне гораздо легче начать с X = data.T
и работать только с X оттуда. Я добавил ваш код "fixed" в конце сообщения.
Получение собственных значений
Вы уже заметили, что вы можете получить собственные векторы, используя clf.components_
.
Таким образом, у вас есть основные компоненты. Они являются собственными векторами ковариационной матрицы $ X ^ TX $.
Способ извлечения собственных значений оттуда состоит в том, чтобы применить эту матрицу к каждому главному компоненту и проецировать результаты на компонент. Пусть v_1 - первый главный компонент и lambda_1 - соответствующее собственное значение. У нас есть:
и таким образом: с . (x, y) - скалярное произведение векторов x и y.
Назад в Python вы можете сделать:
n_samples = X.shape[0]
# We center the data and compute the sample covariance matrix.
X -= np.mean(X, axis=0)
cov_matrix = np.dot(X.T, X) / n_samples
for eigenvector in pca.components_:
print(np.dot(eigenvector.T, np.dot(cov_matrix, eigenvector)))
И вы получаете собственное значение, связанное с собственным вектором. Ну, в моих тестах оказалось, что не работать с парами последних собственных значений, но я бы отнесла это к отсутствию навыков в числовой стабильности.
Теперь это не лучший способ получить собственные значения, но приятно знать, откуда они взялись.
Собственные значения представляют собой дисперсию в направлении собственного вектора. Поэтому вы можете получить их через атрибут pca.explained_variance_
:
eigenvalues = pca.explained_variance_
Вот воспроизводимый пример, который печатает собственные значения, которые вы получаете с каждым методом:
import numpy as np
from sklearn.decomposition import PCA
from sklearn.datasets import make_classification
X, y = make_classification(n_samples=1000)
n_samples = X.shape[0]
pca = PCA()
X_transformed = pca.fit_transform(X)
# We center the data and compute the sample covariance matrix.
X_centered = X - np.mean(X, axis=0)
cov_matrix = np.dot(X_centered.T, X_centered) / n_samples
eigenvalues = pca.explained_variance_
for eigenvalue, eigenvector in zip(eigenvalues, pca.components_):
print(np.dot(eigenvector.T, np.dot(cov_matrix, eigenvector)))
print(eigenvalue)
Исходный код, исправленный
Если вы запустите его, вы увидите, что значения согласованы. Они не совсем равны, потому что numpy и scikit-learn не используют один и тот же алгоритм здесь.
Главное, чтобы вы использовали корреляционную матрицу вместо ковариации, как упоминалось выше. Также вы получали транспонированные собственные векторы из numpy, что делало его очень запутанным.
import numpy as np
from scipy.stats.mstats import zscore
from sklearn.decomposition import PCA
def pca_code(data):
#raw_implementation
var_per=.98
data-=np.mean(data, axis=0)
# data/=np.std(data, axis=0)
cov_mat=np.cov(data, rowvar=False)
evals, evecs = np.linalg.eigh(cov_mat)
idx = np.argsort(evals)[::-1]
evecs = evecs[:,idx]
evals = evals[idx]
variance_retained=np.cumsum(evals)/np.sum(evals)
index=np.argmax(variance_retained>=var_per)
evecs = evecs[:,:index+1]
reduced_data=np.dot(evecs.T, data.T).T
print("evals", evals)
print("_"*30)
print(evecs.T[1, :])
print("_"*30)
#using scipy package
clf=PCA(var_per)
X_train=data
X_train=clf.fit_transform(X_train)
print(clf.explained_variance_)
print("_"*30)
print(clf.components_[1,:])
print("__"*30)
Надеюсь, что это поможет, не стесняйтесь просить разъяснений.