Анализ основных компонентов и регрессия в Python

11

Я пытаюсь понять, как воспроизвести в Python какую-то работу, которую я проделал в SAS. Используя этот набор данных , где мультиколлинеарность является проблемой, я хотел бы выполнить анализ основных компонентов в Python. Я смотрел на scikit-learn и statsmodels, но я не уверен, как взять их результаты и преобразовать их в ту же структуру результатов, что и в SAS. Во-первых, SAS, кажется, выполняет PCA на корреляционной матрице, когда вы используете PROC PRINCOMP, но большинство (все?) Библиотек Python, похоже, используют SVD.

В наборе данных первый столбец является переменной ответа, а следующие 5 являются прогнозирующими переменными, называемыми pred1-pred5.

В SAS общий рабочий процесс:

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

Я знаю, что последний шаг работает только потому, что я выбираю только ПК1 и ПК2 по порядку.

Итак, в Python, это примерно, насколько я получил:

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)

Количество отклонений, которое объясняет каждый компьютер?

print pca.explained_variance_ratio_

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

Что это? Собственные векторы?

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

Это собственные значения?

print pca.explained_variance_

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

Я немного растерялся из-за того, как получить от результатов Python фактическое выполнение регрессии главных компонентов (в Python). Заполняет ли какая-либо из библиотек Python пробелы аналогично SAS?

Любые советы приветствуются. Я немного избалован использованием меток в выходных данных SAS, и я не очень знаком с пандами, numpy, scipy или scikit-learn.


Редактировать:

Таким образом, похоже, что sklearn не будет работать напрямую с данным фреймом pandas. Допустим, я конвертирую его в массив numpy:

npa = frame2.values
npa

Вот что я получаю:

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

Если я затем изменю copyпараметр PCA sklearn, False,он будет работать непосредственно с массивом, согласно комментарию ниже.

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

npa

В соответствии с выводом, похоже, что он заменил все значения npaвместо добавления чего-либо в массив. Какие ценности npaсейчас? Главный компонент оценки для исходного массива?

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
В scikit-learn каждый образец сохраняется в виде строки в вашей матрице данных. Класс PCA работает непосредственно с матрицей данных, т. Е. Он заботится о вычислении ковариационной матрицы, а затем ее собственных векторов. Что касается ваших последних 3 вопросов, да, компоненты_ являются собственными векторами ковариационной матрицы, объясненные_вариантные_рации_ являются дисперсией, которую объясняет каждый компьютер, и объясненная дисперсия должна соответствовать собственным значениям.
Lightalchemist
@ lightalchemist Спасибо за разъяснения. С sklearn, правильно ли создавать новый кадр данных до выполнения PCA, или можно отправить в «полный» кадр данных pandas, и он не будет работать в крайнем левом столбце (ответ)?
Глина
Я добавил немного больше информации. Если я сначала преобразую в пустой массив, а затем запускаю PCA copy=False, я получаю новые значения. Это главные оценки компонентов?
Глина
Я не очень знаком с Пандами, поэтому у меня нет ответа на эту часть вашего вопроса. Что касается второй части, я не думаю, что они являются основным компонентом. Я считаю, что они являются исходными образцами данных, но со средним вычитанием. Тем не менее, я не могу быть в этом уверен.
Lightalchemist

Ответы:

16

Scikit-learn не имеет комбинированной реализации PCA и регрессии, как, например, пакет pls в R. Но я думаю, что можно сделать как ниже или выбрать регрессию 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()

Масштабирование и преобразование данных для получения главных компонентов

X_reduced = pca.fit_transform(scale(X))

Дисперсия (% кумулятивная) объясняется основными компонентами

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

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

Похоже, что первые два компонента действительно объясняют большую часть различий в данных.

10-кратное резюме с тасовкой

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

regr = LinearRegression()
mse = []

Сделайте одно резюме, чтобы получить MSE только для перехвата (без основных компонентов в регрессии)

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) 

Сделайте резюме для 5 основных компонентов, добавив один компонент к регрессии в то время

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

введите описание изображения здесь

Научный регресс 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))

введите описание изображения здесь

Jordi
источник
7

Вот SVD только на Python и NumPy (годы спустя).
(Это не решает ваши вопросы о SSA / sklearn / pandas вообще, но может когда-нибудь помочь питонисту .)

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


-> журнал

# 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]
Денис
источник
Я немного опоздал на вечеринку, но отличный ответ
plumbus_bouquet
3

Попробуйте использовать конвейер, чтобы объединить анализ основных компонентов и линейную регрессию:

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

Мой ответ приходит почти на пять лет позже, и есть большая вероятность, что вам больше не понадобится помощь в проведении ПЦР в Python. Мы разработали пакет Python с именем hoggorm, который делает именно то, что вам было нужно. Пожалуйста, посмотрите на примеры ПЦР здесь . Существует также дополнительный пакет для построения графиков с именем hoggormplot для визуализации результатов, рассчитанных с помощью hoggorm.

оли
источник