PCA w numpy i sklearn daje różne wyniki

21

Czy coś nie rozumiem? To jest mój kod

za pomocą 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)

Wynik:

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]])

Korzystanie z metod 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)

Wynik

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.

Czy mogę wiedzieć, dlaczego tak jest?

Jeśli chcę odzyskać pierwotną matrycę, co powinienem zrobić?

aceminer
źródło
Twój kod numpy jest nieprawidłowy IMHO (używa również tego, Xco nie zostało zdefiniowane). Sprawdź swoją matematykę .
Anony-Mousse -Reinstate Monica
Korzystam z notatnika ipython, więc mogłem kopiować tylko komórki. Moja matematyka jest w błędzie? Która część @ Anony-Mousse
aceminer
@ Anony-Mousse Tak, zdałem sobie sprawę z mojego błędu, ale nadal nie pasuje
aceminer
@aceminer Jestem ciekawy, dlaczego obliczasz macierz kowariancji x_std.T, a nie x_std?
Evgeni Nabokov
@EvgeniNabokov było za długo. Sry, nie pamiętam już
aceminer

Odpowiedzi:

21

Różnica polega na tym, że decomposition.PCAnie standaryzuje zmiennych przed wykonaniem PCA, podczas gdy w obliczeniach ręcznych wywołuje StandardScalersię standaryzację. Stąd obserwujesz tę różnicę: PCA w korelacji czy kowariancji?

Jeśli wymienisz

pca.fit_transform(x)

z

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

uzyskasz taki sam wynik jak w przypadku obliczeń ręcznych ...

... ale tylko do kolejności komputerów. To dlatego, że kiedy biegniesz

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

otrzymujesz wartości własne niekoniecznie w malejącej kolejności. dostaję

array([ 0.07168571,  2.49382602,  1.43448827])

Więc będziesz chciał zamówić je ręcznie. Sklearn robi to za Ciebie.


Jeśli chodzi o rekonstrukcję oryginalnych zmiennych, zobacz Jak odwrócić PCA i zrekonstruować oryginalne zmienne z kilku głównych składników?

ameba mówi Przywróć Monikę
źródło
Chciałbym tylko sprawdzić. Czy naprawdę konieczna jest standaryzacja matrycy według jej odchylenia standardowego? Widziałem przykłady, w których tego nie robią
aceminer
Nie jest to konieczne , jest to tylko jeden ze sposobów. Zobacz link, który umieściłem w pierwszym akapicie: stats.stackexchange.com/questions/53 - tak naprawdę chodzi o to pytanie. Jeśli ustandaryzujesz, zrobisz PCA na korelacjach. Jeśli nie, robisz PCA na kowariancjach.
ameba mówi Przywróć Monikę
9

Oto ładna implementacja z dyskusją i wyjaśnieniem PCA w pythonie. Ta implementacja prowadzi do tego samego rezultatu co scikit PCA. To kolejny wskaźnik, że twój PCA jest zły.

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)

musisz posortować wartości własne (i odpowiednio wektory własne) malejąco

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

a = np.dot(x, evecs) 

Ogólnie polecam sprawdzenie kodu poprzez implementację prostego przykładu (tak prostego, jak to możliwe) i ręczne obliczenie poprawnych wyników (i wyników pośrednich). Pomaga to zidentyfikować problem.

Nikolas Rieble
źródło
1
Uwielbiam tę odpowiedź. To rozwiązało mój problem!
Jinhua Wang