📄 multilogit.m
字号:
function results = multilogit(y,x,beta0,maxit,tol);
% PURPOSE: implements multinomial logistic regression
% Pr(y_i=j) = exp(x_i'beta_j)/sum_l[exp(x_i'beta_l)]
% where:
% i = 1,2,...,nobs
% j,l = 0,1,2,...,ncat
%-------------------------------------------------------------------------%
% USAGE: results = multilogit(y,x,beta)
% where: y = response variable vector (nobs x 1)
% the response variable should be coded sequentially from 0 to
% ncat, i.e., y in {0,1,2,...,ncat}
% x = matrix of covariates (nobs x nvar)
% NOTE: to include a constant term in each beta_j,
% include a column of ones in x
% beta0 = optional starting values for beta (nvar x ncat+1) (default=0)
% maxit = optional maximum number of iterations (default=100)
% tol = optional convergence tolerance (default=1e-6)
%-------------------------------------------------------------------------%
% RETURNS: a structure
% results.meth = 'multilogit'
% results.beta_mat = (nvar x ncat) matrix of beta coefficients:
% [beta_1 beta_2 ... beta_ncat] under the
% normalization beta_0 = 0
% results.beta_vec = (nvar*ncat x 1) vector of beta coefficients:
% [beta_1 ; beta_2 ; ... ; beta_ncat] under
% normalization beta_0 = 0
% results.covb = (nvar*ncat x nvar*ncat) covariance matrix
% of results.beta_vec
% results.tstat_mat = matrix of t-statistics conformable to
% results.beta_mat
% results.tstat_vec = vector of t-statistics conformable to
% results.beta_vec
% results.yfit = (nobs x ncat+1) matrix of fitted
% probabilities: [P_0 P_1 ... P_ncat]
% where P_j = [P_1j ; P_2j ; ... ; P_nobsj]
% results.lik = unrestricted log likelihood
% results.cnvg = convergence criterion
% results.iter = number of iterations
% results.nobs = number of observations
% results.nvar = number of variables
% results.ncat = number of categories of dependent variable
% (including the reference category j = 0)
% results.count = vector of counts of each value taken by y, i.e.,
% count = [#y=0 #y=1 ... #y=ncat]
% results.y = y vector
% results.lratio = LR test statistic against intercept-only model (all
% betas=0), distributed chi-squared with (nvar-1)*ncat
% degrees of freedom
% results.rsqr = McFadden pseudo-R^2
%
%-------------------------------------------------------------------------%
% A NOTE: Since users might prefer results (coefficients and tstats) in
% either a vector or matrix format, and since there is no single natural
% representation for these in the multinomial logit model, the results
% structure returns both. Note that the input arguments require that
% (optional) starting values in matrix (nvar x ncat) format.
%
%-------------------------------------------------------------------------%
% SEE ALSO: prt_multilogit, multilogit_lik
%-------------------------------------------------------------------------%
% References: Greene (1997), p.914
% written by:
% Simon D. Woodcock
% CISER / Economics
% Cornell University
% Ithaca, NY
% sdw9@cornell.edu
%---------------------------------------------------------%
% ERROR CHECKING AND PRELIMINARY CALCULATIONS %
%---------------------------------------------------------%
if nargin < 2, error('multilogit: wrong # of input arguments'); end;
y = round(y(:)); [nobs cy]=size(y); [rx nvar]=size(x);
if (rx~=nobs), error('multilogit: row dimensions of x and y must agree'); end;
% initial calculations
xstd = [1 std(x(:,2:nvar))];
x = x ./ ( ones(nobs,1)*xstd ); % standardize x
ymin = min(y);
ymax = max(y);
ncat = ymax - ymin;
d0 = ( y*ones(1,ncat+1) ) == ( ones(nobs,1)*(ymin:ymax) ); % put y in dummy format
d = d0(:,2:ncat+1); % normalize beta_0 = 0
% starting values
if nargin < 3
beta0 = zeros(nvar,ncat+1);
else
[a b] = size(beta0);
if a == 0
beta0 = zeros(nvar,ncat+1);
else for j = 1:ncat;
beta0(:,j) = beta0(:,j) .* xstd';
end;
end;
end;
beta = beta0(:,2:ncat+1);
% default max iterations and tolerance
if nargin < 4 , maxit = 100; tol = 1e-6; end;
if nargin < 5 , tol = 1e-6; end;
if nargin > 6 , error('multilogit: wrong # of arguments'); end;
% check nvar and ncat are consistently defined;
[rbeta cbeta] = size(beta);
if nvar ~= rbeta
error('multilogit: rows of beta and columns of x do not agree')
end;
if ncat ~= cbeta
error(['multilogit: number of columns in beta and categories in y do not agree. ' ...
'check that y is numbered continuously, i.e., y takes values in {0,1,2,3,4,5}' ...
' is ok, y takes values in {0,1,2,3,4,99} is not.'])
end;
%----------------------------------------------------%
% MAXIMUM LIKELIHOOD ESTIMATION OF MULTINOMIAL LOGIT %
%----------------------------------------------------%
% likelihood and derivatives at starting values
[P,lnL] = multilogit_lik(y,x,beta,d);
[g H] = multilogit_deriv(x,d,P,nvar,ncat,nobs);
iter=0;
for j = 1:ncat % vectorize beta and gradient for newton-raphson update
f = (j-1)*nvar + 1;
l = j*nvar;
vb(f:l,1) = beta(:,j);
vg(f:l,1) = g(:,j);
end;
% newton-raphson update
while (abs(vg'*(H\vg)/length(vg)) > tol) & (iter < maxit)
iter = iter + 1;
betaold = beta;
vbold = vb;
vb = vbold - H\vg;
for j = 1:ncat % de-vectorize updated beta for pass to multilogit_lik
f = (j-1)*nvar + 1;
l = j*nvar;
beta(:,j) = vb(f:l,1);
end;
[P,lnL] = multilogit_lik(y,x,beta,d); % update P, lnL
[g H] = multilogit_deriv(x,d,P,nvar,ncat,nobs); % update g,H
for j = 1:ncat; % vectorize updated g for next N-R update
f = (j-1)*nvar + 1;
l = j*nvar;
vg(f:l,1) = g(:,j);
end;
disp(['iteration: ' num2str(iter)]);
disp(['log-likelihood: ' num2str(lnL)]);
end;
%---------------------------------------------------------%
% GENERATE RESULTS STRUCTURE %
%---------------------------------------------------------%
results.meth = 'multilogit';
for j = 1:ncat
results.beta_mat(:,j) = beta(:,j) ./ xstd'; % restore original scale
end;
for j = 1:ncat
f = (j-1)*nvar + 1;
l = j*nvar;
results.beta_vec(f:l,1) = results.beta_mat(:,j);
end;
results.covb = -inv(H)./kron(ones(ncat),(xstd'*xstd)); % restore original scale
stdb = sqrt(diag(results.covb));
results.tstat_vec = results.beta_vec./stdb;
for j = 1:ncat
f = (j-1)*nvar + 1;
l = j*nvar;
results.tstat_mat(:,j) = results.tstat_vec(f:l,1);
end;
P_0 = ones(nobs,1) - sum(P')';
results.yfit = [P_0 P];
results.lik = lnL;
results.cnvg = tol;
results.iter = iter;
results.nobs = nobs;
results.nvar = nvar;
results.ncat = ncat;
results.count = [nobs-sum(sum(d)') sum(d)];
results.y = y;
% basic specification testing;
p = results.count / nobs;
lnLr = nobs*sum((p.*log(p))'); % restricted log-likelihood: intercepts only
results.lratio = -2*(lnLr - results.lik);
results.rsqr = 1 - (results.lik / lnLr); % McFadden pseudo-R^2
%---------------------------------------------------------%
% SUPPLEMENTARY FUNCTION FOR COMPUTING DERIVATIVES %
%---------------------------------------------------------%
function [g,H] = multilogit_deriv(x,d,P,nvar,ncat,nobs);
% PURPOSE: Computes gradient and Hessian of multinomial logit
% model
% ---------------------------------------------------------
% References: Greene (1997), p.914
% written by:
% Simon D. Woodcock
% CISER / Economics
% 201 Caldwell Hall
% Cornell University
% Ithaca, NY 14850
% sdw9@cornell.edu
% compute gradient matrix (nvar x ncat)
tmp = d - P;
g = x'*tmp;
% compute Hessian, which has (ncat)^2 blocks of size (nvar x nvar)
% this algorithm builds each block individually, m&n are block indices
H = zeros(nvar*ncat);
for m = 1:ncat;
for n = 1:ncat;
fr = (m-1)*nvar + 1;
lr = m*nvar;
fc = (n-1)*nvar + 1;
lc = n*nvar;
index = (n==m);
index = repmat(index,nobs,1);
H(fr:lr,fc:lc) = -( ( x.*( P(:,m)*ones(1,nvar) ) )' * ( x.*( (index-P(:,n))*ones(1,nvar) ) ) ) ;
end;
end;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -