Comment puis-je obtenir les valeurs propres et les vecteurs propres de l'application PCA?
from sklearn.decomposition import PCA
clf=PCA(0.98,whiten=True) #converse 98% variance
X_train=clf.fit_transform(X_train)
X_test=clf.transform(X_test)
Je ne le trouve pas dans docs .
1.Je ne suis "pas" en mesure de comprendre les différents résultats ici.
Modifier :
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)
print("_"*30)
print(evecs)
print("_"*30)
#using scipy package
clf=PCA(var_per)
X_train=data.T
X_train=clf.fit_transform(X_train)
print(clf.explained_variance_)
print("_"*30)
print(clf.components_)
print("__"*30)
Vous calculez les vecteurs propres de la matrice de corrélation , c'est-à-dire la matrice de covariance des variables normalisées.data/=np.std(data, axis=0)
ne fait pas partie de l'APC classique, nous centrons uniquement les variables. Ainsi, le sklearn PCA ne propose pas de mise à l'échelle des données au préalable .
En dehors de cela, vous êtes sur la bonne voie, si nous faisons abstraction du fait que le code que vous avez fourni ne s'est pas exécuté;). Vous avez seulement été confondu avec les dispositions de ligne/colonne. Honnêtement, je pense qu'il est beaucoup plus facile de commencer par X = data.T
et travailler uniquement avec X à partir de là. J'ai ajouté votre code "fixe" à la fin du post.
Vous avez déjà noté que vous pouvez obtenir les vecteurs propres en utilisant clf.components_
.
Vous avez donc les principaux composants. Ce sont des vecteurs propres de la matrice - covariance $ X ^ T X $.
Un moyen de récupérer les valeurs propres à partir de là est d'appliquer cette matrice à chaque composant principal et de projeter les résultats sur le composant. Soit v_1 le premier composant principal et lambda_1 la valeur propre associée. On a:
et donc: depuis . (x, y) le produit scalaire des vecteurs x et y.
De retour en Python vous pouvez faire:
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)))
Et vous obtenez la valeur propre associée au vecteur propre. Eh bien, dans mes tests, il s'est avéré ne pas fonctionner avec les dernières valeurs propres du couple, mais j'attribuerais cela à mon absence de compétences en stabilité numérique.
Ce n'est pas la manière la meilleure d'obtenir les valeurs propres mais c'est bien de savoir d'où elles viennent.
Les valeurs propres représentent la variance dans la direction du vecteur propre. Vous pouvez donc les faire passer par le pca.explained_variance_
attribut:
eigenvalues = pca.explained_variance_
Voici un exemple reproductible qui imprime les valeurs propres que vous obtenez avec chaque méthode:
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)
Si vous l'exécutez, vous verrez que les valeurs sont cohérentes. Ils ne sont pas exactement égaux car numpy et scikit-learn n'utilisent pas le même algorithme ici.
L'essentiel était que vous utilisiez la matrice de corrélation au lieu de la covariance, comme mentionné ci-dessus. De plus, vous obteniez les transposés vecteurs propres de numpy, ce qui était très déroutant.
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)
J'espère que cela vous aide, n'hésitez pas à demander des clarifications.
J'ai utilisé la fonction sklearn PCA. Les paramètres de retour "composants_" sont des vecteurs propres et "explication_variance_" sont des valeurs propres. Voici mon code de test.
from sklearn.decomposition import PCA
import numpy as np
def main():
data = np.array([[2.5, 2.4], [0.5, 0.7], [2.2, 2.9], [1.9, 2.2], [3.1, 3.0], [2.3, 2.7], [2, 1.6], [1, 1.1], [1.5, 1.6], [1.1, 0.9]])
print(data)
pca = PCA()
pca.fit(data)
print(pca.components_)
print(pca.explained_variance_)
if __name__ == "__main__":
main()