Analiza i regresja głównych składników w języku Python

11

Próbuję wymyślić, jak odtworzyć w Pythonie niektóre prace, które wykonałem w SAS. Korzystając z tego zestawu danych , gdzie problemem jest wielokoliniowość, chciałbym przeprowadzić analizę głównych składników w Pythonie. Przyjrzałem się scikit-learn i statsmodels, ale nie jestem pewien, jak wykorzystać ich dane wyjściowe i przekonwertować je na tę samą strukturę wyników, co SAS. Po pierwsze, SAS wydaje się wykonywać PCA na macierzy korelacji podczas używania PROC PRINCOMP, ale wydaje się , że większość (wszystkich?) Bibliotek Pythona używa SVD.

W zestawie danych pierwsza kolumna jest zmienną odpowiedzi, a następne 5 to zmienne predykcyjne, zwane pred1-pred5.

W SAS ogólny przepływ pracy to:

/* Get the PCs */
proc princomp data=indata out=pcdata;
    var pred1 pred2 pred3 pred4 pred5;
run;

/* Standardize the response variable */
proc standard data=pcdata mean=0 std=1 out=pcdata2;
    var response;
run;

/* Compare some models */
proc reg data=pcdata2;
    Reg:     model response = pred1 pred2 pred3 pred4 pred5 / vif;
    PCa:     model response = prin1-prin5 / vif;
    PCfinal: model response = prin1 prin2 / vif;
run;
quit;

/* Use Proc PLS to to PCR Replacement - dropping pred5 */
/* This gets me my parameter estimates for the original data */
proc pls data=indata method=pcr nfac=2;
    model response = pred1 pred2 pred3 pred4 / solution;
run;
quit;

Wiem, że ostatni krok działa tylko dlatego, że wybieram kolejno PC1 i PC2.

W Pythonie chodzi o to, o ile mi się udało:

import pandas as pd
import numpy  as np
from sklearn.decomposition.pca import PCA

source = pd.read_csv('C:/sourcedata.csv')

# Create a pandas DataFrame object
frame = pd.DataFrame(source)

# Make sure we are working with the proper data -- drop the response variable
cols = [col for col in frame.columns if col not in ['response']]
frame2 = frame[cols]

pca = PCA(n_components=5)
pca.fit(frame2)

Ile wariancji wyjaśnia każdy komputer?

print pca.explained_variance_ratio_

Out[190]:
array([  9.99997603e-01,   2.01265023e-06,   2.70712663e-07,
         1.11512302e-07,   2.40310191e-09])

Co to jest? Wektory własne?

print pca.components_

Out[179]:
array([[ -4.32840645e-04,  -7.18123771e-04,  -9.99989955e-01,
         -4.40303223e-03,  -2.46115129e-05],
       [  1.00991662e-01,   8.75383248e-02,  -4.46418880e-03,
          9.89353169e-01,   5.74291257e-02],
       [ -1.04223303e-02,   9.96159390e-01,  -3.28435046e-04,
         -8.68305757e-02,  -4.26467920e-03],
       [ -7.04377522e-03,   7.60168675e-04,  -2.30933755e-04,
          5.85966587e-02,  -9.98256573e-01],
       [ -9.94807648e-01,  -1.55477793e-03,  -1.30274879e-05,
          1.00934650e-01,   1.29430210e-02]])

Czy to są wartości własne?

print pca.explained_variance_

Out[180]:
array([  8.07640319e+09,   1.62550137e+04,   2.18638986e+03,
         9.00620474e+02,   1.94084664e+01])

Nie wiem, jak przejść z wyników w Pythonie do faktycznego wykonywania głównej regresji składników (w Pythonie). Czy którakolwiek z bibliotek Python wypełnia puste pola podobnie jak SAS?

Wszelkie wskazówki są mile widziane. Trochę mnie rozpieszczają używanie etykiet w danych wyjściowych SAS i nie znam się dobrze na pandach, numpy, scipy lub scikit-learn.


Edytować:

Wygląda więc na to, że sklearn nie będzie działać bezpośrednio na ramce danych pand. Powiedzmy, że przekonwertowałem go na tablicę numpy:

npa = frame2.values
npa

Oto co otrzymuję:

Out[52]:
array([[  8.45300000e+01,   4.20730000e+02,   1.99443000e+05,
          7.94000000e+02,   1.21100000e+02],
       [  2.12500000e+01,   2.73810000e+02,   4.31180000e+04,
          1.69000000e+02,   6.28500000e+01],
       [  3.38200000e+01,   3.73870000e+02,   7.07290000e+04,
          2.79000000e+02,   3.53600000e+01],
       ..., 
       [  4.71400000e+01,   3.55890000e+02,   1.02597000e+05,
          4.07000000e+02,   3.25200000e+01],
       [  1.40100000e+01,   3.04970000e+02,   2.56270000e+04,
          9.90000000e+01,   7.32200000e+01],
       [  3.85300000e+01,   3.73230000e+02,   8.02200000e+04,
          3.17000000e+02,   4.32300000e+01]])

Jeśli następnie zmienię copyparametr PCA sklearn, aby False,działał on bezpośrednio na tablicy, zgodnie z komentarzem poniżej.

pca = PCA(n_components=5,copy=False)
pca.fit(npa)

npa

Według danych wyjściowych wygląda na to, że zastąpił wszystkie wartości npazamiast dodawać cokolwiek do tablicy. Jakie są npateraz wartości ? Zasadnicze wyniki komponentu dla oryginalnej tablicy?

Out[64]:
array([[  3.91846649e+01,   5.32456568e+01,   1.03614689e+05,
          4.06726542e+02,   6.59830027e+01],
       [ -2.40953351e+01,  -9.36743432e+01,  -5.27103110e+04,
         -2.18273458e+02,   7.73300268e+00],
       [ -1.15253351e+01,   6.38565684e+00,  -2.50993110e+04,
         -1.08273458e+02,  -1.97569973e+01],
       ..., 
       [  1.79466488e+00,  -1.15943432e+01,   6.76868901e+03,
          1.97265416e+01,  -2.25969973e+01],
       [ -3.13353351e+01,  -6.25143432e+01,  -7.02013110e+04,
         -2.88273458e+02,   1.81030027e+01],
       [ -6.81533512e+00,   5.74565684e+00,  -1.56083110e+04,
         -7.02734584e+01,  -1.18869973e+01]])
Glina
źródło
1
W scikit-learn każda próbka jest przechowywana jako wiersz w macierzy danych. Klasa PCA działa bezpośrednio na macierzy danych, tj. Zajmuje się obliczeniem macierzy kowariancji , a następnie jej wektorów własnych. Jeśli chodzi o twoje ostatnie 3 pytania, tak, komponenty_ są wektorami własnymi macierzy kowariancji, wyjaśnione_ wariancje_wartości są wariancją, którą wyjaśnia każdy komputer, a wyjaśniona wariancja powinna odpowiadać wartościom własnym.
lightalchemist
@lightalchemist Dziękujemy za wyjaśnienie. W przypadku sklearn, czy właściwe jest utworzenie nowej ramki danych przed wykonaniem PCA, czy też możliwe jest przesłanie ramki danych „kompletnych” pand i czy nie działa ona w lewej kolumnie (odpowiedzi)?
Clay
Dodałem trochę więcej informacji. Jeśli najpierw przekonwertuję na tablicę numpy, a następnie uruchomię PCA copy=False, otrzymam nowe wartości. Czy są to główne wyniki punktowe?
Clay
Nie znam się na Pandach, więc nie mam odpowiedzi na tę część twojego pytania. Jeśli chodzi o drugą część, nie sądzę, aby były one głównym elementem. Uważam, że są to oryginalne próbki danych, ale ze średnią odjętą. Jednak tak naprawdę nie mogę być tego pewien.
lightalchemist

Odpowiedzi:

16

Scikit-learn nie ma połączonej implementacji PCA i regresji, jak na przykład pakiet pls w R. Ale myślę, że można zrobić jak poniżej lub wybrać regresję PLS.

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

from sklearn.preprocessing import scale
from sklearn.decomposition import PCA
from sklearn import cross_validation
from sklearn.linear_model import LinearRegression

%matplotlib inline

import seaborn as sns
sns.set_style('darkgrid')

df = pd.read_csv('multicollinearity.csv')
X = df.iloc[:,1:6]
y = df.response

Scikit-learn PCA

pca = PCA()

Skaluj i przekształcaj dane, aby uzyskać główne składniki

X_reduced = pca.fit_transform(scale(X))

Odchylenie (% skumulowane) wyjaśnione przez główne składniki

np.cumsum(np.round(pca.explained_variance_ratio_, decimals=4)*100)

array([  73.39,   93.1 ,   98.63,   99.89,  100.  ])

Wydaje się, że dwa pierwsze składniki rzeczywiście wyjaśniają większość wariancji danych.

10-krotne CV, z tasowaniem

n = len(X_reduced)
kf_10 = cross_validation.KFold(n, n_folds=10, shuffle=True, random_state=2)

regr = LinearRegression()
mse = []

Wykonaj jedno CV, aby uzyskać MSE dla samego przechwytywania (bez głównych elementów regresji)

score = -1*cross_validation.cross_val_score(regr, np.ones((n,1)), y.ravel(), cv=kf_10, scoring='mean_squared_error').mean()    
mse.append(score) 

Wykonaj CV dla 5 głównych składników, dodając jednocześnie jeden element do regresji

for i in np.arange(1,6):
    score = -1*cross_validation.cross_val_score(regr, X_reduced[:,:i], y.ravel(), cv=kf_10, scoring='mean_squared_error').mean()
    mse.append(score)

fig, (ax1, ax2) = plt.subplots(1,2, figsize=(12,5))
ax1.plot(mse, '-v')
ax2.plot([1,2,3,4,5], mse[1:6], '-v')
ax2.set_title('Intercept excluded from plot')

for ax in fig.axes:
    ax.set_xlabel('Number of principal components in regression')
    ax.set_ylabel('MSE')
    ax.set_xlim((-0.2,5.2))

wprowadź opis zdjęcia tutaj

Scikit-learn regresja PLS

mse = []

kf_10 = cross_validation.KFold(n, n_folds=10, shuffle=True, random_state=2)

for i in np.arange(1, 6):
    pls = PLSRegression(n_components=i, scale=False)
    pls.fit(scale(X_reduced),y)
    score = cross_validation.cross_val_score(pls, X_reduced, y, cv=kf_10, scoring='mean_squared_error').mean()
    mse.append(-score)

plt.plot(np.arange(1, 6), np.array(mse), '-v')
plt.xlabel('Number of principal components in PLS regression')
plt.ylabel('MSE')
plt.xlim((-0.2, 5.2))

wprowadź opis zdjęcia tutaj

Jordi
źródło
7

Oto SVD tylko w Pythonie i NumPy (lata później).
(To nie dotyczy w ogóle twoich pytań na temat SSA / sklearn / pandas, ale może kiedyś pomóc pythonistowi .)

#!/usr/bin/env python2
""" SVD straight up """
# geometry: see http://www.ams.org/samplings/feature-column/fcarc-svd

from __future__ import division
import sys
import numpy as np

__version__ = "2015-06-15 jun  denis-bz-py t-online de"

# from bz.etc import numpyutil as nu
def ints( x ):
    return np.round(x).astype(int)  # NaN Inf -> - maxint

def quantiles( x ):
    return "quantiles %s" % ints( np.percentile( x, [0, 25, 50, 75, 100] ))


#...........................................................................
csvin = "ccheaton-multicollinearity.csv"  # https://gist.github.com/ccheaton/8393329
plot = 0

    # to change these vars in sh or ipython, run this.py  csvin=\"...\"  plot=1  ...
for arg in sys.argv[1:]:
    exec( arg )

np.set_printoptions( threshold=10, edgeitems=10, linewidth=120,
    formatter = dict( float = lambda x: "%.2g" % x ))  # float arrays %.2g

#...........................................................................
yX = np.loadtxt( csvin, delimiter="," )
y = yX[:,0]
X = yX[:,1:]
print "read %s" % csvin
print "y %d  %s" % (len(y), quantiles(y))
print "X %s  %s" % (X.shape, quantiles(X))
print ""

#...........................................................................
U, sing, Vt = np.linalg.svd( X, full_matrices=False )
#...........................................................................

print "SVD: %s -> U %s . sing diagonal . Vt %s" % (
        X.shape, U.shape, Vt.shape )
print "singular values:", ints( sing )
    # % variance (sigma^2) explained != % sigma explained, e.g. 10 1 1 1 1

var = sing**2
var *= 100 / var.sum()
print "% variance ~ sing^2:", var

print "Vt, the right singular vectors  * 100:\n", ints( Vt * 100 )
    # multicollinear: near +- 100 in each row / col

yU = y.dot( U )
yU *= 100 / yU.sum()
print "y ~ these percentages of U, the left singular vectors:", yU


-> log

# from: test-pca.py
# run: 15 Jun 2015 16:45  in ~bz/py/etc/data/etc  Denis-iMac 10.8.3
# versions: numpy 1.9.2  scipy 0.15.1   python 2.7.6   mac 10.8.3

read ccheaton-multicollinearity.csv
y 373  quantiles [  2823  60336  96392 147324 928560]
X (373, 5)  quantiles [     7     47    247    573 512055]

SVD: (373, 5) -> U (373, 5) . sing diagonal . Vt (5, 5)
singular values: [2537297    4132    2462     592      87]
% variance ~ sing^2: [1e+02 0.00027 9.4e-05 5.4e-06 1.2e-07]
Vt, the right singular vectors  * 100:
[[  0   0 100   0   0]
 [  1  98   0 -12  17]
 [-10 -11   0 -99  -6]
 [  1 -17   0  -4  98]
 [-99   2   0  10   2]]
y ~ these percentages of U, the left singular vectors: [1e+02 15 -18 0.88 -0.57]
denis
źródło
Jestem trochę spóźniony na imprezę, ale świetna odpowiedź
plumbus_bouquet
4

Spróbuj użyć potoku do połączenia analizy podstawowych składników i regresji liniowej:

from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
from sklearn.linear_model import LinearRegression
from sklearn.pipeline import Pipeline

# Principle components regression
steps = [
    ('scale', StandardScaler()),
    ('pca', PCA()),
    ('estimator', LinearRegression())
]
pipe = Pipeline(steps)
pca = pipe.set_params(pca__n_components=3)
pca.fit(X, y)
Joe
źródło
3

Moja odpowiedź nadchodzi prawie pięć lat z opóźnieniem i istnieje duża szansa, że ​​nie potrzebujesz już dłużej pomocy w wykonywaniu PCR w Pythonie. Opracowaliśmy pakiet Python o nazwie hoggorm, który robi dokładnie to, czego wtedy potrzebowałeś. Proszę spojrzeć na przykłady PCR tutaj . Istnieje również komplementarny pakiet kreślarski o nazwie hoggormplot do wizualizacji wyników obliczanych za pomocą hoggorma.

oli
źródło