Nine algorithms

I got a request to send the code of the nine algo­rithms that were com­pared in “A com­par­i­son of nine PLS1 algo­rithms” and pub­lished in the Jour­nal of Chemo­met­rics 2009; 23: 518–529 and led to the Kowal­ski price 2010 for best the­o­ret­i­cal paper. Then I thought it would be even bet­ter if they would be eas­ily avail­able for every­one, and that it would be best to pub­lish them here on this blog.

The con­clu­sion of the paper still holds but it could be added that not only defla­tion will give the best numer­i­cal pre­ci­sion. Using mod­i­fied Gram-Schmidt orthog­o­nal­iza­tions on the PLS load­ing and score vec­tors will also lead to numer­i­cally sta­ble results. On the other hand, when think­ing about it, the mod­i­fied Gram-Schmidt orthog­o­nal­iza­tion is a kind of defla­tion too.

One more thing that I have noticed after pub­lish­ing that could be worth a com­ment is that the imple­men­ta­tions of Krylov PLS and PLSPLS could be as fast as the fastest algo­rithms if a the mut­li­pli­ca­tion of X would be stored in a tem­po­rary vari­able, but any­way they will never belong to the top class of numer­i­cal pre­ci­sion, so per­haps it does not mat­ter much.

Any­way, here we go with the orig­i­nal code that was published:

NIPALS by Wold

func­tion [b,p,q,w,t] = nipals_pls1(x,y,A);
for a = 1:A,
v = x’*y;
w(:,a) = v/sqrt(v’*v);
t(:,a) = x*w(:,a);
tt = t(:,a)’*t(:,a);
p(:,a) = x’*t(:,a)/tt;
x = x‑t(:,a)*p(:,a)’;
q(a,1) = t(:,a)’*y/tt;
end
b = cum­sum(w*(inv(p’*w)*diag(q’)),2);

Non-orthog­o­nal­ized scores algo­rithm by Martens

func­tion [b,w,t] = nonorth_scorespls1(x,y,A);
y0 = y;
for a = 1:A
v = x’*y;
w(:,a) = v/sqrt(v’*v);
t(:,a) = x*w(:,a);
qA = inv(t’*t)*t’*y0;
% uncom­ment for best stability
% qA = t\y0;
b(:,a) = w*qA;
x = x‑t(:,a)*w(:,a)’;
y = y0‑t*qA;
end

Bidiag2 by Golub and Kahan

func­tion [b,w,t,B] = bidiag2(x,y,A);
w(:,1) = x’*y;
w(:,1) = w(:,1)/norm(w(:,1));
t(:,1) = x*w(:,1);
B(1,1) = norm(t(:,1));
t(:,1) = t(:,1)/B(1,1);
for a = 2:A,
w(:,a) = x’*t(:,a-1)-B(a-1,a-1)*w(:,a-1);
B(a-1,a) = norm(w(:,a));
w(:,a) = w(:,a)/B(a-1,a);
t(:,a) = x*w(:,a)-B(a-1,a)*t(:,a-1);
B(a,a) = norm(t(:,a));
t(:,a) = t(:,a)/B(a,a);
end
invB = inv(B);
q = y’*t;
for a = 1:A,
b(:,a) = w(:,1:a)*(invB(1:a,1:a)*q(1:a));
end

SIMPLS by de Jong

func­tion [b,R,T,P,Q] = simpls1(x,y,A)
[tmp,K] = size(x);
V = zeros(K,A);
s = x’*y;
for a = 1:A
r = s;
t = x*r;
tt = norm(t);
t = t/tt;
r = r/tt;
p = x’*t;
q = y’*t;
u = y*q;
v = p;
if a > 1
v = v — V*(V’*p);
u = u — T*(T’*u);
end
v = v/norm(v);
s = s — v*(v’*s);
R(:,a) = r;
T(:,a) = t;
P(:,a) = p;
Q(:,a) = q;
U(:,a) = u;
V(:,a) = v;
end
b = cum­sum(R*diag(Q),2);

Improved ker­nel PLS by Dayal

func­tion [b,W,P,T,Q,R] = impr_kernel1(X,Y,A);
W=[];R=[];P=[];Q=[];T=[];U=[];
XY=X’*Y;
for a=1:A
w=XY;
w=w/sqrt(w’*w);
r=w;
for k=1:a-1,
r=r-(P(:,k)’*w)*R(:,k);
end
t = X*r;
tt = t’*t;
p = X’*t/tt;
q = (r’*XY)’/tt;
XY = XY-(p*q’)*tt;
W = [W w];
P = [P p];
T = [T t];
Q = [Q q];
R = [R r];
end
b = cum­sum(R*diag(Q’),2);

PLSF by Manne

func­tion b = plsf(x,y,A);
W(:,1) = x’*y;
nw1 = norm(W(:,1));
W(:,1) = W(:,1)/nw1;
U = x*W(:,1);
Rd(1) = norm(U);
U = U/Rd(1);
Uy(1) = U’*y;
k = 1;
while k > 0,
k = k+1;
W(:,k) = x’*U‑W(:,k-1)*Rd(k-1);
Ru(k-1) = norm(W(:,k));
W(:,k) = W(:,k)/Ru(k-1);
if k > A,
break;
else
U = x*W(:,k)-U*Ru(k-1);
Rd(k) = norm(U);
U = U/Rd(k);
Uy(k) = U’*y;
end
end
W(:,k) = [];
Ru(k-1) = [];
n1 = k-1;
R = zeros(n1,n1);
R = R+diag(Rd)+diag(Ru,1);
Uy = Uy’;
invR = inv(R);
for k = 1:A,
b(:,k) = W(:,1:k)*(invR(1:k,1:k)*Uy(1:k));
end

Direct-scores PLS by Andersson

func­tion [b,U,R,P,q] = directscorespls1(x,y,A)
s = x’*y;
utemp = x*s;
nrm = norm(utemp);
R(:,1) = s/nrm;
U(:,1) = utemp/nrm;
P(:,1) = x’*U(:,1);
q(:,1) = y’*U(:,1);
b(:,1) = R*q’;
for a = 2:A,
s = s‑P(:,a-1)*q(:,a-1)’;
rtemp = s — R*(P’*s);
utemp = x*rtemp;
nrm = norm(utemp);
R(:,a) = rtemp/nrm;
U(:,a) = utemp/nrm;
P(:,a) = x’*U(:,a);
q(:,a) = y’*U(:,a);
b(:,a) = R*q’;
end

Krylov PLS1 by Andersson

func­tion b = krylovpls1(x,y,A)
V = x’*y;
b = V*((x*V)\y);
for a = 2:A
V = [V x’*(x*V(:,a-1))];
b(:,a) = V*((x*V)\y);
end

PLSPLS1 by Andersson

func­tion b = plspls1(x,y,A)
V = x’*y;
b = V*((x*V)\y);
for a = 2:A
V = [b x’*(x*b(:,a-1))];
b(:,a) = V*((x*V)\y);
end

Leave a Comment

Your email address will not be published. Required fields are marked *

This website uses cookies. By continuing to use this site, you accept our use of cookies. 

Scroll to Top