ECG-Kit 1.0
(9,423 bytes)
%pls_train Partial Least Squares (training)
%
% [B,XRes,YRes,Options] = pls_train(X,Y)
% [B,XRes,YRes,Options] = pls_train(X,Y,Options)
%
% INPUT
% X [N -by- d_X] the training (input) data matrix, N samples, d_X variables
% Y [N -by- d_Y] the training (output) data matrix, N samples, d_Y variables
%
% Options.
% maxLV maximal number of latent variables (will be corrected
% if > rank(X));
% maxLV=inf means maxLV=min(N,d_X) -- theoretical maximum
% number of LV;
% by default =inf
% method 'NIPALS' or 'SIMPLS'; by default ='SIMPLS'
%
% X_centering do nothing (=[] or 0), do mean centering (=nan), center
% around some vaue v (=v);
% by default =[]
% Y_centering do nothing (=[] or 0), do mean centering (=nan), center
% around some vaue v (=v);
% by default =[]
% X_scaling do nothing (=[] or 1), divide each col by std (=nan),
% divide by some v (=v);
% by default =[]
% Y_scaling do nothing (=[] or 1), divide each col by std (=nan),
% divide by some v (=v);
% by default =[]
%
% OUTPUT
% B [d_X -by- d_Y -by- nLV] collection of regression matrices:
% Y_new = X_new*B(:,:,n) represents regression on the first n
% latent variables (X_new here after preprocessing, Y_new before
% un-preprocessing)
% XRes.
% ssq [1 -by- nLV] the part of explaind sum of squares of
% (preprocessed) X matrix
% T [N -by- nLV] scores (transformed (preprocessed) X)
% R [d_X -by- nLV] weights (transformation matrix)
% P [d_X -by- nLV] loadings (back-transformation matrix)
% P(:,k) are the regression coef of
% (preprocessed) X on T(:,k)
% W [d_X -by- nLV] local weights (local transformation matrix);
% ONLY FOR NIPALS
% V [d_X -by- nLV] first k columns of this matrix are the
% orthornormal basis of the space spanned by k
% first columns of P; ONLY FOR SIMPLS
% YRes.
% ssq [1 -by- nLV] the part of explained sum of squares of
% (preprocessed) Y matrix
% U [N -by- nLV] scores (transformed (preprocessed) Y)
% Q [d_Y -by- nLV] weights (transformation matrix)
% C [d_Y -by- nLV] C(:,k) are the regression coeff of
% (preprocessed) Y on T(:,k)
% bin [1 -by- nLV] bin(k) is the regression coeff of U(:,k) on T(:,k)
%
% Options. contains the same fields as in input, but the values can be changed
% (e.g. after mean centering X_centering = mean(X,1))
%
% DESCRIPTION
% Trains PLS (Partial Least Squares) regression model
%
% Relations between matrices (X end Y are assumed to be preprocessed):
% NIPALS:
% T = X*R (columns of T are orthogonal)
% R = W*prinv(P'*W)
% P = X'*T*prinv(T'*T)
% U = Y*Q - T*(C'*Q-tril(C'*Q))
% C = Y'*T*prinv(T'*T) = Q*diag(bin)
% bin = sqrt(diag(T'*Y*Y'*T))'*prinv(T'*T))
% B = R*C' = W*prinv(P'*W)*C'
%
% SIMPLS:
% T = X*R (columns of T are orthonormal)
% P = X'*T
% U = Y*Q
% C = Y'*T = Q*diag(bin)
% bin = sqrt(diag(T'*Y*Y'*T))'
% B = R*C'
%
% BOTH:
% T_new = X_new*R
% Y_new = X_new*B
%
% SEE ALSO (<a href="http://37steps.com/prtools">PRTools Guide</a>)
% PLS_APPLY, PLS_TRANSFORM
% Copyright: S.Verzakov, s.verzakov@ewi.tudelft.nl
% Faculty EWI, Delft University of Technology
% P.O. Box 5031, 2600 GA Delft, The Netherlands
% $Id: pls_train.m,v 1.2 2010/02/08 15:29:48 duin Exp $
function [B, XRes, YRes, Options] = pls_train(X,Y,Options)
[N_X, d_X] = size(X);
[N_Y, d_Y] = size(Y);
if N_X ~= N_Y
error('size(X,1) must be equal to size(Y,1)');
else
N = N_X;
end
if nargin < 3
Options = [];
end
DefaultOptions.X_centering = [];
DefaultOptions.Y_centering = [];
DefaultOptions.X_scaling = [];
DefaultOptions.Y_scaling = [];
DefaultOptions.maxLV = inf;
DefaultOptions.method = 'SIMPLS';
Options = pls_updstruct(DefaultOptions, Options);
if isinf(Options.maxLV)
Options.maxLV = min(N,d_X);
elseif Options.maxLV > min(N,d_X)
error('PLS: The number of LV(s) cannot be greater then min(N,d_X)');
end
[X, Options.X_centering, Options.X_scaling] = pls_prepro(X, Options.X_centering, Options.X_scaling);
[Y, Options.Y_centering, Options.Y_scaling] = pls_prepro(Y, Options.Y_centering, Options.Y_scaling);
ssq_X = sum(X(:).^2);
ssq_Y = sum(Y(:).^2);
B = zeros(d_X,d_Y,Options.maxLV);
XRes.ssq = zeros(1,Options.maxLV);
XRes.T = zeros(N,Options.maxLV);
XRes.R = zeros(d_X,Options.maxLV);
XRes.P = zeros(d_X,Options.maxLV);
XRes.W = [];
XRes.V = [];
YRes.ssq = zeros(1,Options.maxLV);
YRes.U = zeros(N,Options.maxLV);
YRes.Q = zeros(d_Y,Options.maxLV);
YRes.C = zeros(d_Y,Options.maxLV);
YRes.bin = zeros(1,Options.maxLV);
ev = zeros(1,Options.maxLV);
nLV = Options.maxLV;
opts.disp = 0;
opts.issym = 1;
opts.isreal = 1;
switch upper(Options.method)
case 'NIPALS'
XRes.W = zeros(d_X,Options.maxLV);
for LV = 1:Options.maxLV
S = X'*Y;
if d_X <= d_Y
if d_X > 1
[w, ev(LV)] = eigs(S*S',1,'LA',opts);
else
w = 1;
ev(LV) = S*S';
end
t = X*w;
t2 = (t'*t);
proj = t/t2;
p = X'*proj;
c = Y'*proj;
bin = norm(c); %bin = sqrt(ev)/t2:
q = c/bin;
u = Y*q;
else
if d_Y > 1
[q, ev(LV)] = eigs(S'*S,1,'LA',opts);
else
q = 1;
ev(LV) = S'*S;
end
u = Y*q;
w = X'*u;
w = w/norm(w);
t = X*w;
t2 = (t'*t);
proj = t/t2;
p = X'*proj;
bin = u'*proj; %bin = sqrt(ev)/t2:
c = q*bin;
end
if LV == 1
if ev(LV) == 0
error('PLS: Rank of the covariation matrix X''*Y is zero.');
end
elseif ev(LV) <= 1e-16*ev(1)
nLV = LV-1;
WarnMsg = sprintf(['\nPLS: Rank of the covariation matrix X''*Y is exausted ' ...
'after removing %d Latent Variable(s).\n'...
'Results only for the %d LV(s) will be returned'],nLV,nLV);
if exist('prwarning')
prwarning(1, WarnMsg);
else
warning(WarnMsg);
end
break;
end
%R = W*prinv(P'*W)
%the next portion of the code makes use of the fact taht P'*W is the upper triangle matrix:
%
%if LV == 1
% InvPTW(1,1) = 1/(p'*w);
% r = w*InvPTW(1,1);
%else
% InvPTW(1:LV,LV) = [(-InvPTW(1:LV-1,1:LV-1)*(XRes.P(:,1:LV-1)'*w)); 1]/(p'*w);
% r = [XRes.W(:,1:LV-1), w] * InvPTW(1:LV,LV);
%end
%
%some optimization of the above code (notice that ones(m,0)*ones(0,n) == zeros(m,n)):
%
r = (w - (XRes.R(:,1:LV-1)*(XRes.P(:,1:LV-1)'*w)))/(p'*w);
B(:,:,LV) = r*c';
XRes.ssq(:,LV) = t2*(p'*p)/ssq_X;
XRes.T(:,LV) = t;
XRes.R(:,LV) = r;
XRes.P(:,LV) = p;
XRes.W(:,LV) = w;
YRes.ssq(:,LV) = t2*(bin.^2)/ssq_Y;
YRes.U(:,LV) = u;
YRes.Q(:,LV) = q;
YRes.C(:,LV) = c;
YRes.bin(:,LV) = bin;
X = X - t*p';
Y = Y - t*c';
end
if nLV < Options.maxLV
XRes.W = XRes.W(:,1:nLV);
end
case 'SIMPLS'
XRes.V = zeros(d_X,Options.maxLV);
S = X'*Y;
for LV = 1:Options.maxLV
if d_X <= d_Y
if d_X > 1
[r, ev(LV)] = eigs(S*S',1,'LA',opts);
else
r = 1;
ev(LV) = S*S';
end
t = X*r;
norm_t = norm(t);
r = r/norm_t;
t = t/norm_t;
p = X'*t;
c = Y'*t; %c = S'*r;
bin = norm(c); %bin = sqrt(ev)/norm_t:
q = c/bin;
u = Y*q;
else
if d_Y > 1
[q, ev(LV)] = eigs(S'*S,1,'LA',opts);
else
q = 1;
ev(LV) = S'*S;
end
r = S*q;
t = X*r;
norm_t = norm(t);
r = r/norm_t;
t = t/norm_t;
p = X'*t;
u = Y*q;
bin = u'*t; %bin = ev/norm_t:
c = q*bin;
end
if LV == 1
if ev(LV) == 0
error('PLS: Rank of the covariation matrix X''*Y is zero.');
else
v = p;
end
elseif ev(LV) <= 1e-16*ev(1)
nLV = LV-1;
WarnMsg = sprintf(['\nPLS: Rank of the covariation matrix X''*Y is exausted ' ...
'after removing %d Latent Variable(s).\n'...
'Results only for the %d LV(s) will be returned'],nLV,nLV);
if exist('prwarning')
prwarning(1, WarnMsg);
else
warning(WarnMsg);
end
break;
else
v = p - XRes.V(:,1:LV-1)*(XRes.V(:,1:LV-1)'*p);
end
v = v/norm(v);
B(:,:,LV) = r*c';
XRes.ssq(:,LV) = (p'*p)/ssq_X;
XRes.T(:,LV) = t;
XRes.R(:,LV) = r;
XRes.P(:,LV) = p;
XRes.V(:,LV) = v;
YRes.ssq(:,LV) = (bin.^2)/ssq_Y;
YRes.U(:,LV) = u;
YRes.Q(:,LV) = q;
YRes.C(:,LV) = c;
YRes.bin(:,LV) = bin;
S = S - v*(v'*S);
end
if nLV < Options.maxLV
XRes.V = XRes.V(:,1:nLV);
end
end
if nLV < Options.maxLV
B = B(:,:,1:nLV);
XRes.ssq = XRes.ssq(:,1:nLV);
XRes.T = XRes.T(:,1:nLV);
XRes.R = XRes.R(:,1:nLV);
XRes.P = XRes.P(:,1:nLV);
YRes.ssq = YRes.ssq(:,1:nLV);
YRes.U = YRes.U(:,1:nLV);
YRes.Q = YRes.Q(:,1:nLV);
YRes.C = YRes.C(:,1:nLV);
YRes.bin = YRes.bin(:,1:nLV);
Options.maxLV = nLV;
end
B = cumsum(B,3);
return;
function A = MakeSym(A)
A = 0.5*(A+A');
%A = max(A,A');
return