2011-02-01 20:58:27 +08:00
|
|
|
"""
|
|
|
|
|
=========================
|
|
|
|
|
PLS Partial Least Squares
|
|
|
|
|
=========================
|
|
|
|
|
|
|
|
|
|
Simple usage of various PLS flavor:
|
|
|
|
|
- PLSCanonical
|
|
|
|
|
- PLSRegression, with multivariate response, a.k.a. PLS2
|
|
|
|
|
- PLSRegression, with univariate response, a.k.a. PLS1
|
|
|
|
|
- CCA
|
2011-03-25 07:27:18 +08:00
|
|
|
|
|
|
|
|
Given 2 multivariate covarying two-dimensional datasets, X, and Y,
|
|
|
|
|
PLS extracts the 'directions of covariance', i.e. the components of each
|
|
|
|
|
datasets that explain the most shared variance between both datasets.
|
|
|
|
|
This is apparent on the **scatterplot matrix** display: components 1 in
|
|
|
|
|
dataset X and dataset Y are maximaly correlated (points lie around the
|
|
|
|
|
first diagonal). This is also true for components 2 in both dataset,
|
|
|
|
|
however, the correlation across datasets for different components is
|
|
|
|
|
weak: the point cloud is very spherical.
|
2011-02-01 20:58:27 +08:00
|
|
|
"""
|
2011-06-05 00:15:44 +08:00
|
|
|
print __doc__
|
2011-02-01 20:58:27 +08:00
|
|
|
|
2011-01-30 10:42:28 +08:00
|
|
|
import numpy as np
|
|
|
|
|
import pylab as pl
|
2011-09-02 17:00:02 +08:00
|
|
|
from sklearn.pls import PLSCanonical, PLSRegression, CCA
|
2011-01-23 12:50:08 +08:00
|
|
|
|
2011-12-20 01:16:51 +08:00
|
|
|
###############################################################################
|
2011-02-01 20:58:27 +08:00
|
|
|
# Dataset based latent variables model
|
2011-01-30 10:42:28 +08:00
|
|
|
|
2011-02-01 11:35:18 +08:00
|
|
|
n = 500
|
2011-01-30 10:42:28 +08:00
|
|
|
# 2 latents vars:
|
2011-02-01 11:35:18 +08:00
|
|
|
l1 = np.random.normal(size=n)
|
|
|
|
|
l2 = np.random.normal(size=n)
|
|
|
|
|
|
|
|
|
|
latents = np.array([l1, l1, l2, l2]).T
|
2011-12-20 01:16:51 +08:00
|
|
|
X = latents + np.random.normal(size=4 * n).reshape((n, 4))
|
|
|
|
|
Y = latents + np.random.normal(size=4 * n).reshape((n, 4))
|
2011-02-01 11:35:18 +08:00
|
|
|
|
2011-12-20 01:16:51 +08:00
|
|
|
X_train = X[:n / 2]
|
|
|
|
|
Y_train = Y[:n / 2]
|
|
|
|
|
X_test = X[n / 2:]
|
|
|
|
|
Y_test = Y[n / 2:]
|
2011-01-30 10:42:28 +08:00
|
|
|
|
|
|
|
|
print "Corr(X)"
|
2011-02-01 11:35:18 +08:00
|
|
|
print np.round(np.corrcoef(X.T), 2)
|
2011-01-30 10:42:28 +08:00
|
|
|
print "Corr(Y)"
|
2011-02-01 11:35:18 +08:00
|
|
|
print np.round(np.corrcoef(Y.T), 2)
|
2011-01-23 02:04:57 +08:00
|
|
|
|
2011-12-20 01:16:51 +08:00
|
|
|
###############################################################################
|
2011-02-01 20:58:27 +08:00
|
|
|
# Canonical (symetric) PLS
|
2011-01-23 02:04:57 +08:00
|
|
|
|
2011-01-28 02:33:59 +08:00
|
|
|
# Transform data
|
2011-01-30 03:48:43 +08:00
|
|
|
# ~~~~~~~~~~~~~~
|
2011-08-30 17:54:20 +08:00
|
|
|
plsca = PLSCanonical(n_components=2)
|
|
|
|
|
plsca.fit(X_train, Y_train)
|
2011-02-01 11:35:18 +08:00
|
|
|
X_train_r, Y_train_r = plsca.transform(X_train, Y_train)
|
|
|
|
|
X_test_r, Y_test_r = plsca.transform(X_test, Y_test)
|
2011-01-30 10:42:28 +08:00
|
|
|
|
|
|
|
|
# Scatter plot of scores
|
|
|
|
|
# ~~~~~~~~~~~~~~~~~~~~~~
|
2011-02-01 11:35:18 +08:00
|
|
|
# 1) on diagonal plot X vs Y scores on each components
|
2011-01-30 10:42:28 +08:00
|
|
|
pl.subplot(221)
|
2011-02-01 11:35:18 +08:00
|
|
|
pl.plot(X_train_r[:, 0], Y_train_r[:, 0], "ob", label="train")
|
|
|
|
|
pl.plot(X_test_r[:, 0], Y_test_r[:, 0], "or", label="test")
|
2011-01-30 10:42:28 +08:00
|
|
|
pl.xlabel("y")
|
|
|
|
|
pl.ylabel("x")
|
2011-02-01 20:58:27 +08:00
|
|
|
pl.title('Comp. 1, corr = %.2f' %
|
2011-02-01 11:35:18 +08:00
|
|
|
np.corrcoef(X_test_r[:, 0], X_test_r[:, 0])[0, 1])
|
2011-01-30 10:42:28 +08:00
|
|
|
pl.legend()
|
2011-01-27 22:21:13 +08:00
|
|
|
|
2011-01-30 10:42:28 +08:00
|
|
|
pl.subplot(224)
|
2011-02-01 11:35:18 +08:00
|
|
|
pl.plot(X_train_r[:, 1], Y_train_r[:, 1], "ob", label="train")
|
|
|
|
|
pl.plot(X_test_r[:, 1], Y_test_r[:, 1], "or", label="test")
|
2011-01-30 10:42:28 +08:00
|
|
|
pl.xlabel("y")
|
|
|
|
|
pl.ylabel("x")
|
2011-02-01 20:58:27 +08:00
|
|
|
pl.title('Comp. 2, corr = %.2f' %
|
2011-02-01 11:35:18 +08:00
|
|
|
np.corrcoef(X_test_r[:, 1], X_test_r[:, 1])[0, 1])
|
2011-01-30 10:42:28 +08:00
|
|
|
pl.legend()
|
2011-01-28 02:33:59 +08:00
|
|
|
|
2011-02-01 11:35:18 +08:00
|
|
|
# 2) Off diagonal plot components 1 vs 2 for X and Y
|
|
|
|
|
pl.subplot(222)
|
|
|
|
|
pl.plot(X_train_r[:, 0], X_train_r[:, 1], "*b", label="train")
|
|
|
|
|
pl.plot(X_test_r[:, 0], X_test_r[:, 1], "*r", label="test")
|
2011-01-30 10:42:28 +08:00
|
|
|
pl.xlabel("X comp. 1")
|
|
|
|
|
pl.ylabel("X comp. 2")
|
2011-02-01 11:35:18 +08:00
|
|
|
pl.title('X, corr = %.2f' % np.corrcoef(X_test_r[:, 0], X_test_r[:, 1])[0, 1])
|
2011-01-30 10:42:28 +08:00
|
|
|
pl.legend()
|
|
|
|
|
|
|
|
|
|
pl.subplot(223)
|
2011-02-01 11:35:18 +08:00
|
|
|
pl.plot(Y_train_r[:, 0], Y_train_r[:, 1], "*b", label="train")
|
|
|
|
|
pl.plot(Y_test_r[:, 0], Y_test_r[:, 1], "*r", label="test")
|
2011-01-30 10:42:28 +08:00
|
|
|
pl.xlabel("Y comp. 1")
|
|
|
|
|
pl.ylabel("Y comp. 2")
|
2011-02-01 11:35:18 +08:00
|
|
|
pl.title('Y, corr = %.2f' % np.corrcoef(Y_test_r[:, 0], Y_test_r[:, 1])[0, 1])
|
2011-01-30 10:42:28 +08:00
|
|
|
pl.legend()
|
|
|
|
|
pl.show()
|
2011-01-27 22:21:13 +08:00
|
|
|
|
2011-12-20 01:16:51 +08:00
|
|
|
###############################################################################
|
2011-02-01 20:58:27 +08:00
|
|
|
# PLS regression, with multivariate response, a.k.a. PLS2
|
2011-01-23 02:04:57 +08:00
|
|
|
|
2011-02-01 11:35:18 +08:00
|
|
|
n = 1000
|
|
|
|
|
q = 3
|
|
|
|
|
p = 10
|
|
|
|
|
X = np.random.normal(size=n * p).reshape((n, p))
|
|
|
|
|
B = np.array([[1, 2] + [0] * (p - 2)] * q).T
|
2011-01-31 19:11:05 +08:00
|
|
|
# each Yj = 1*X1 + 2*X2 + noize
|
2011-02-01 11:35:18 +08:00
|
|
|
Y = np.dot(X, B) + np.random.normal(size=n * q).reshape((n, q)) + 5
|
2011-01-31 19:11:05 +08:00
|
|
|
|
2011-08-30 17:54:20 +08:00
|
|
|
pls2 = PLSRegression(n_components=3)
|
|
|
|
|
pls2.fit(X, Y)
|
2011-01-31 19:11:05 +08:00
|
|
|
print "True B (such that: Y = XB + Err)"
|
|
|
|
|
print B
|
|
|
|
|
# compare pls2.coefs with B
|
|
|
|
|
print "Estimated B"
|
2011-02-01 11:35:18 +08:00
|
|
|
print np.round(pls2.coefs, 1)
|
2011-01-30 03:48:43 +08:00
|
|
|
pls2.predict(X)
|
2011-01-17 23:23:53 +08:00
|
|
|
|
2011-12-20 01:16:51 +08:00
|
|
|
###############################################################################
|
2011-02-01 20:58:27 +08:00
|
|
|
# PLS regression, with univariate response, a.k.a. PLS1
|
|
|
|
|
|
2011-02-01 11:35:18 +08:00
|
|
|
n = 1000
|
|
|
|
|
p = 10
|
2011-12-20 01:16:51 +08:00
|
|
|
X = np.random.normal(size=n * p).reshape((n, p))
|
2011-02-01 11:35:18 +08:00
|
|
|
y = X[:, 0] + 2 * X[:, 1] + np.random.normal(size=n * 1) + 5
|
2011-08-30 17:54:20 +08:00
|
|
|
pls1 = PLSRegression(n_components=3)
|
|
|
|
|
pls1.fit(X, y)
|
2011-01-31 19:11:05 +08:00
|
|
|
# note that the number of compements exceeds 1 (the dimension of y)
|
|
|
|
|
print "Estimated betas"
|
2011-02-01 11:35:18 +08:00
|
|
|
print np.round(pls1.coefs, 1)
|
2011-01-31 19:11:05 +08:00
|
|
|
|
2011-12-20 01:16:51 +08:00
|
|
|
###############################################################################
|
2011-02-01 20:58:27 +08:00
|
|
|
# CCA (PLS mode B with symetric deflation)
|
2011-01-31 19:11:05 +08:00
|
|
|
|
2011-08-30 17:54:20 +08:00
|
|
|
cca = CCA(n_components=2)
|
|
|
|
|
cca.fit(X_train, Y_train)
|
2011-02-01 11:35:18 +08:00
|
|
|
X_train_r, Y_train_r = plsca.transform(X_train, Y_train)
|
|
|
|
|
X_test_r, Y_test_r = plsca.transform(X_test, Y_test)
|