Analisi e regressione dei componenti principali in Python


11

Sto cercando di capire come riprodurre in Python alcuni lavori che ho svolto in SAS. Utilizzando questo set di dati , in cui la multicollinearità è un problema, vorrei eseguire l'analisi dei componenti principali in Python. Ho esaminato scikit-learn e statsmodels, ma non sono sicuro di come ottenere il loro output e convertirlo nella stessa struttura di risultati di SAS. Per prima cosa, SAS sembra eseguire PCA sulla matrice di correlazione quando si utilizza PROC PRINCOMP, ma la maggior parte (tutte?) Delle librerie Python sembrano utilizzare SVD.

Nel set di dati , la prima colonna è la variabile di risposta e le successive 5 sono variabili predittive, denominate pred1-pred5.

In SAS, il flusso di lavoro generale è:

/* 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;

So che l'ultimo passaggio funziona solo perché sto solo scegliendo PC1 e PC2, in ordine.

Quindi, in Python, questo è tutto per quanto ho ottenuto:

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)

La quantità di varianza che ogni PC spiega?

print pca.explained_variance_ratio_

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

Cosa sono questi? Autovettori?

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

Sono questi gli autovalori?

print pca.explained_variance_

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

Sono un po 'a corto di come ottenere dai risultati di Python per eseguire effettivamente la regressione dei componenti principali (in Python). Una delle librerie di Python riempie gli spazi vuoti in modo simile a SAS?

Eventuali suggerimenti sono apprezzati. Sono un po 'viziato dall'uso delle etichette nell'output SAS e non ho molta familiarità con i panda, intorpidito, scipy o scikit-learn.


Modificare:

Quindi, sembra che sklearn non operi direttamente su un frame di dati Panda. Diciamo che lo converto in un array intorpidito:

npa = frame2.values
npa

Ecco cosa ottengo:

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

Se poi modifico il copyparametro del PCA di sklearn in modo False,che funzioni direttamente sull'array, secondo il commento qui sotto.

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

npa

Per l'output, sembra che abbia sostituito tutti i valori npainvece di aggiungere qualcosa all'array. Quali sono i valori npaadesso? I punteggi dei componenti principali per l'array originale?

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

1
In scikit-learn, ogni campione viene archiviato come una riga nella matrice dei dati. La classe PCA opera direttamente sulla matrice di dati, cioè si occupa del calcolo della matrice di covarianza e quindi dei suoi autovettori. Per quanto riguarda le ultime 3 domande, sì, i componenti_ sono gli autovettori della matrice di covarianza, spiega_variance_ratio_ sono la varianza spiegata da ciascun PC e la varianza spiegata dovrebbe corrispondere agli autovalori.
lightalchemist

@lightalchemist Grazie per il chiarimento. Con sklearn, è corretto creare un nuovo frame di dati prima di eseguire il PCA, oppure è possibile inviare il frame di dati panda "completo" e non farlo funzionare nella colonna più a sinistra (risposta)?
Clay,

Ho aggiunto qualche informazione in più. Se converto prima in un array numpy e poi eseguo PCA con copy=False, ottengo nuovi valori. Quelli sono i punteggi dei componenti principali?
Clay

Non conosco molto bene i Panda, quindi non ho una risposta a quella parte della tua domanda. Per quanto riguarda la seconda parte, non penso che siano il componente principale. Credo che siano i campioni di dati originali ma con la media sottratta. Tuttavia, non posso davvero esserne sicuro.
Lightalchemist,

Risposte:


16

Scikit-learn non ha un'implementazione combinata di PCA e regressione come ad esempio il pacchetto pls in R. Ma penso che si possa fare come sotto o scegliere la regressione 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()

Ridimensionare e trasformare i dati per ottenere i componenti principali

X_reduced = pca.fit_transform(scale(X))

Varianza (% cumulativa) spiegata dai componenti principali

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

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

Sembra che i primi due componenti spieghino davvero la maggior parte della varianza nei dati.

CV 10 volte, con riproduzione casuale

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

regr = LinearRegression()
mse = []

Fai un CV per ottenere MSE solo per l'intercettazione (nessun componente principale in regressione)

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) 

Fai CV per i 5 componenti principali, aggiungendo un componente alla regressione in quel momento

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

inserisci qui la descrizione dell'immagine

Regressione PLS di Scikit-learn

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

inserisci qui la descrizione dell'immagine


7

Ecco SVD solo in Python e NumPy (anni dopo).
(Questo non affronta affatto le tue domande su SSA / sklearn / panda, ma un giorno potrebbe aiutare un pitonista .)

#!/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


-> registro

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

Sono un po 'in ritardo alla festa ma ottima risposta
plumbus_bouquet

3

Prova a utilizzare una pipeline per combinare l'analisi dei componenti principali e la regressione lineare:

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)

3

La mia risposta arriverà con quasi cinque anni di ritardo e ci sono buone probabilità che tu non abbia più bisogno di aiuto per fare la PCR in Python. Abbiamo sviluppato un pacchetto Python chiamato hoggorm che fa esattamente ciò di cui avevi bisogno allora. Dai un'occhiata agli esempi di PCR qui . Esiste anche un pacchetto di stampa complementare chiamato hoggormplot per la visualizzazione dei risultati calcolati con hoggorm.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.