No BSD License  

Highlights from
Non-negative Garotte

from Non-negative Garotte by Statovic
Implementation of Leo Breiman's non-negative garotte for linear regression

[beta shrcf rss]=nng_garotte(X,y,s)
%% Implementation of L. Breiman's non-negative garrote.
%
% function [beta shrcf rss]=nng_garotte(X,y,s)
% Implementation based on L. Breiman's original FORTRAN code.
%
% Parameters:
%   X     = regressor matrix [n x p]
%   y     = targets [n x 1]
%   s     = garotte constraint parameter [1 x 1]
%
% Returns:
%   beta  = shrunken regression parameters [p x 1]
%   shrcf = shrinkage coefficients [p x 1]
%   rss   = residual sum of squares [1 x 1]
%
% References:
%
% (1) Better Subset Regression Using the Nonnegative Garrote
% Leo Breiman
% Technometrics, Vol. 37, No. 4 (Nov., 1995), pp. 373-384 
%
% (2) A Tutorial on the SWEEP Operator
% James H. Goodnight
% The American Statistician, Vol. 33, No. 3 (Aug., 1979), pp. 149-158 
%
% (3) Solving Least Squares Problems
% Charles L. Lawson and Richard J. Hanson
% pp. 161
%
% (c) Copyright Daniel F. Schmidt and Enes Makalic, 2008

function [beta shrcf rss]=nng_garotte(X,y,s)

%% Initialise variables 
xx=X'*X;
xy=X'*y;
yy=y'*y;
bols=X\y;

%% Solve sum_i c_i < s using the barrier method
con=1000;
tol=0.001;  

xy=bols .* xy / s;
xx=bols*bols' .* xx;
yy=yy/s^2;

done=false;
iters=1;
while(~done && iters < 100)
    xy=xy + (con / s);
    xx=xx + (con / s);
    yy=yy + (con / s);

    % Lawson and Hansen algorithm for solving NNLS
    shrcf=nnls(xx,xy,yy);

    ssum=sum(shrcf);
    shrcf=s*shrcf;

    if(abs(ssum-1.0)>tol)
        con=10*con;
    else
        done=true;
    end;
    
    iters=iters+1;
end;

% Shrunken betas
beta=bols.*shrcf;

% RSS
rss=(y-X*beta)'*(y-X*beta);

%% Solve NNLS by the Lawson and Hansen algorithm
function bt=nnls(xx,xy,yy)

%% Initialise variables
m=length(xx);
z=ones(m,1);
bt=zeros(m,1);
bs=zeros(m,1);
u=zeros(m+1,m+1);

%% Setup 'sweep' matrix
u(1:m,1:m)=xx;
u(1:m,m+1)=xy;
u(m+1,1:m)=xy';
u(m+1,m+1)=yy;

%% Main algorithm
done=false;
loopa=true;
while(~done)

    %% Loop A    
    if(loopa)
        % Compute derivatives w.r.t. beta (Step 2)
        w=xy-xx*bt;

        % If all remaining derivatives are less than zero (Step 3)
        ix=find(z==1);
        if(sum(z) == 0 || max(w(ix)) <= 0)
            return; % we are done
        end;

        % Find the next variable to enter (Step 4)
        [val,wt]=max(w(ix));
        wt=ix(wt);

        % Move the index t from set Z (Step 5)
        z(wt)=0;
        u=sweep(u,wt);
    end;
    
    % Compute the LS solution (Step 6)
    ix=find(z==0);
    bs(ix)=u(ix,m+1);

    % If all coefficients are non-negative, betas are fine (Step 7)
    if(min(bs(ix)) > 0)
        bt=bs;
        loopa=true;
        continue;
    end;
    
    %% Loop B
    loopa=false;

    % (Step 8)
    g=bt ./ (bt - bs);
    ix=find((bs<=0) .* (z == 0));

    % (Step 9)
    alpha=min(g(ix));
    
    % Fix for numerical problems (?)
    if(alpha==0)
            return;
    end;
    
    % (Step 10)
    bt=bt+alpha*(bs-bt);

    % (Step 11)
    [val,ind]=min(g(ix));
    ind=ix(ind);
    u=sweep(u,ind);
end;

%% Sweep operator (Goodnight 1979, page 154)
%  Given a matrix v, and k
function v=sweep(v,k)

m=length(v);
td=v(k,k);

if(td < 1e-10)
    warning('Small');
end;

v(k,:)=v(k,:)/td;
for i=1:m
    if(i == k)
        continue;
    end;
    
    ct=v(i,k);
    v(i,:)=v(i,:)-ct*v(k,:);
    v(i,k)=-ct/td;
end;
v(k,k)=1/td;    

Contact us at files@mathworks.com