Аналіз основних компонентів та регресія в 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;

Я знаю, що останній крок працює лише тому, що я вибираю лише PC1 і PC2, по порядку.

Отже, в 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, і я не дуже знайомий з пандами, нуме, науками або науками.


Редагувати:

Отже, схоже, що sklearn не працюватиме безпосередньо на фреймі даних панди. Скажімо, я перетворюю його в масивний ряд:

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 Дякую за роз’яснення. За допомогою sklearn, чи правильно створити новий фрейм даних перед виконанням PCA, чи можливо надсилати в «повний» фрейм даних панди і чи він не працює в крайньому лівому стовпці (відповіді)?
Глина

Я додав трохи більше інформації. Якщо я перетворюю спочатку масив numpy і потім запускаю PCA copy=False, я отримую нові значення. Це основні бали компонентів?
Глина

Я не так знайомий з Pandas, тому я не маю відповіді на цю частину вашого запитання. Щодо другої частини, я не думаю, що вони є головною складовою. Я вважаю, що вони є оригінальними зразками даних, але із середнім відніманням. Однак я не можу бути впевнений у цьому.
лігтальхімік

Відповіді:


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 від 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))

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


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.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.