O PCA em numpy e sklearn produz resultados diferentes

21

Estou entendendo algo errado. Este é o meu código

usando o sklearn

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from sklearn import decomposition
from sklearn import datasets
from sklearn.preprocessing import StandardScaler

pca = decomposition.PCA(n_components=3)

x = np.array([
        [0.387,4878, 5.42],
        [0.723,12104,5.25],
        [1,12756,5.52],
        [1.524,6787,3.94],
    ])
pca.fit_transform(x)

Resultado:

array([[ -4.25324997e+03,  -8.41288672e-01,  -8.37858943e-03],
   [  2.97275001e+03,  -1.25977271e-01,   1.82476780e-01],
   [  3.62475003e+03,  -1.56843494e-01,  -1.65224286e-01],
   [ -2.34425007e+03,   1.12410944e+00,  -8.87390454e-03]])

Usando métodos numpy

x_std = StandardScaler().fit_transform(x)
cov = np.cov(x_std.T)
ev , eig = np.linalg.eig(cov)
a = eig.dot(x_std.T)

Resultado

array([[ 0.06406894,  0.94063993, -1.62373172],
   [-0.35357757,  0.7509653 ,  0.63365168],
   [ 0.29312477,  0.6710958 ,  1.11766206],
   [-0.00361615, -2.36270102, -0.12758202]])
I have kept all 3 components but it doesnt seem to allow me to retain my original data.

Posso saber por que é assim?

Se eu quiser recuperar minha matriz original, o que devo fazer?

aceminador
fonte
Seu código numpy está errado no IMHO (também usa o Xque não está definido). Verifique novamente sua matemática .
Anony-Mousse - Re
Estou usando o notebook ipython para poder copiar apenas por células. Minha matemática está errada? Que parte @ Anony-Mousse
abr
@ Anony-Mousse Sim, eu percebi o meu erro, mas ele ainda doesnt igualar-se
aceminer
@aceminer Estou curioso por que você calcula a matriz de covariância de x_std.T, não x_std?
Evgeni Nabokov
@EvgeniNabokov já faz muito tempo. Sry eu não me lembro já
propulsor 06/03

Respostas:

21

A diferença é decomposition.PCAque não padroniza suas variáveis ​​antes de executar o PCA, enquanto em seu cálculo manual você solicita StandardScalera padronização. Portanto, você está observando essa diferença: PCA em correlação ou covariância?

Se você substituir

pca.fit_transform(x)

com

x_std = StandardScaler().fit_transform(x)
pca.fit_transform(x_std)

você obterá o mesmo resultado do cálculo manual ...

... mas apenas na ordem dos PCs. Isso porque quando você corre

ev , eig = np.linalg.eig(cov)

você obtém valores próprios, não necessariamente na ordem decrescente. eu recebo

array([ 0.07168571,  2.49382602,  1.43448827])

Então você vai querer encomendá-los manualmente. O Sklearn faz isso por você.


Em relação à reconstrução de variáveis ​​originais, consulte Como reverter o PCA e reconstruir variáveis ​​originais de vários componentes principais?

ameba diz Restabelecer Monica
fonte
Só gostaria de verificar. É realmente necessário padronizar a matriz por seu desvio padrão? Eu visto exemplos onde eles não fazê-lo
aceminer
Não é necessário , é apenas uma maneira de fazê-lo. Veja o link que eu coloquei no primeiro parágrafo: stats.stackexchange.com/questions/53 - é realmente tudo sobre essa questão. Se você padronizar, você executa o PCA nas correlações. Caso contrário, você faz o PCA em covariâncias.
Ameba diz Reinstate Monica
9

Aqui está uma boa implementação com discussão e explicação do PCA em python. Essa implementação leva ao mesmo resultado que o scikit PCA. Esse é outro indicador de que seu PCA está errado.

import numpy as np
from scipy import linalg as LA

x = np.array([
        [0.387,4878, 5.42],
        [0.723,12104,5.25],
        [1,12756,5.52],
        [1.524,6787,3.94],
    ])

#centering the data
x -= np.mean(x, axis = 0)  

cov = np.cov(x, rowvar = False)

evals , evecs = LA.eigh(cov)

você precisa classificar os autovalores (e autovetores de acordo) descendentes

idx = np.argsort(evals)[::-1]
evecs = evecs[:,idx]
evals = evals[idx]

a = np.dot(x, evecs) 

Geralmente, recomendo que você verifique seu código implementando um exemplo simples (o mais simples possível) e calculando manualmente os resultados corretos (e resultados intermediários). Isso ajuda você a identificar o problema.

Nikolas Rieble
fonte
1
Ame esta resposta. Resolveu o meu problema!
Jinhua Wang