1
+ function results = multilogit(y ,x ,beta0 ,maxit ,tol );
2
+ % PURPOSE: implements multinomial logistic regression
3
+ % Pr(y_i=j) = exp(x_i'beta_j)/sum_l[exp(x_i'beta_l)]
4
+ % where:
5
+ % i = 1,2,...,nobs
6
+ % j,l = 0,1,2,...,ncat
7
+ % -------------------------------------------------------------------------%
8
+ % USAGE: results = multilogit(y,x,beta)
9
+ % where: y = response variable vector (nobs x 1)
10
+ % the response variable should be coded sequentially from 0 to
11
+ % ncat, i.e., y in {0,1,2,...,ncat}
12
+ % x = matrix of covariates (nobs x nvar)
13
+ % NOTE: to include a constant term in each beta_j,
14
+ % include a column of ones in x
15
+ % beta0 = optional starting values for beta (nvar x ncat+1) (default=0)
16
+ % maxit = optional maximum number of iterations (default=100)
17
+ % tol = optional convergence tolerance (default=1e-6)
18
+ % -------------------------------------------------------------------------%
19
+ % RETURNS: a structure
20
+ % results.meth = 'multilogit'
21
+ % results.beta_mat = (nvar x ncat) matrix of beta coefficients:
22
+ % [beta_1 beta_2 ... beta_ncat] under the
23
+ % normalization beta_0 = 0
24
+ % results.beta_vec = (nvar*ncat x 1) vector of beta coefficients:
25
+ % [beta_1 ; beta_2 ; ... ; beta_ncat] under
26
+ % normalization beta_0 = 0
27
+ % results.covb = (nvar*ncat x nvar*ncat) covariance matrix
28
+ % of results.beta_vec
29
+ % results.tstat_mat = matrix of t-statistics conformable to
30
+ % results.beta_mat
31
+ % results.tstat_vec = vector of t-statistics conformable to
32
+ % results.beta_vec
33
+ % results.yfit = (nobs x ncat+1) matrix of fitted
34
+ % probabilities: [P_0 P_1 ... P_ncat]
35
+ % where P_j = [P_1j ; P_2j ; ... ; P_nobsj]
36
+ % results.lik = unrestricted log likelihood
37
+ % results.cnvg = convergence criterion
38
+ % results.iter = number of iterations
39
+ % results.nobs = number of observations
40
+ % results.nvar = number of variables
41
+ % results.ncat = number of categories of dependent variable
42
+ % (including the reference category j = 0)
43
+ % results.count = vector of counts of each value taken by y, i.e.,
44
+ % count = [#y=0 #y=1 ... #y=ncat]
45
+ % results.y = y vector
46
+ % results.lratio = LR test statistic against intercept-only model (all
47
+ % betas=0), distributed chi-squared with (nvar-1)*ncat
48
+ % degrees of freedom
49
+ % results.rsqr = McFadden pseudo-R^2
50
+ %
51
+ % -------------------------------------------------------------------------%
52
+ % A NOTE: Since users might prefer results (coefficients and tstats) in
53
+ % either a vector or matrix format, and since there is no single natural
54
+ % representation for these in the multinomial logit model, the results
55
+ % structure returns both. Note that the input arguments require that
56
+ % (optional) starting values in matrix (nvar x ncat) format.
57
+ %
58
+ % -------------------------------------------------------------------------%
59
+ % SEE ALSO: prt_multilogit, multilogit_lik
60
+ % -------------------------------------------------------------------------%
61
+ % References: Greene (1997), p.914
62
+
63
+ % written by:
64
+ % Simon D. Woodcock
65
+ % CISER / Economics
66
+ % Cornell University
67
+ % Ithaca, NY
68
+ % sdw9@cornell.edu
69
+
70
+ % ---------------------------------------------------------%
71
+ % ERROR CHECKING AND PRELIMINARY CALCULATIONS %
72
+ % ---------------------------------------------------------%
73
+
74
+ if nargin < 2 , error(' multilogit: wrong # of input arguments' ); end ;
75
+ y = round(y(: )); [nobs cy ]=size(y ); [rx nvar ]=size(x );
76
+
77
+ if (rx ~= nobs ), error(' multilogit: row dimensions of x and y must agree' ); end ;
78
+
79
+ % initial calculations
80
+ xstd = [1 std(x(: ,2 : nvar ))];
81
+ x = x ./ ( ones(nobs ,1 )*xstd ); % standardize x
82
+ ymin = min(y );
83
+ ymax = max(y );
84
+ ncat = ymax - ymin ;
85
+ d0 = ( y * ones(1 ,ncat + 1 ) ) == ( ones(nobs ,1 )*(ymin : ymax ) ); % put y in dummy format
86
+ d = d0(: ,2 : ncat + 1 ); % normalize beta_0 = 0
87
+
88
+ % starting values
89
+
90
+ if nargin < 3
91
+ beta0 = zeros(nvar ,ncat + 1 );
92
+ else
93
+ [a b ] = size(beta0 );
94
+ if a == 0
95
+ beta0 = zeros(nvar ,ncat + 1 );
96
+ else for j = 1 : ncat ;
97
+ beta0(: ,j ) = beta0(: ,j ) .* xstd ' ;
98
+ end ;
99
+ end ;
100
+ end ;
101
+
102
+ beta = beta0(: ,2 : ncat + 1 );
103
+
104
+ % default max iterations and tolerance
105
+ if nargin < 4 , maxit = 100 ; tol = 1e-6 ; end ;
106
+ if nargin < 5 , tol = 1e-6 ; end ;
107
+
108
+ if nargin > 6 , error(' multilogit: wrong # of arguments' ); end ;
109
+
110
+ % check nvar and ncat are consistently defined;
111
+ [rbeta cbeta ] = size(beta );
112
+ if nvar ~= rbeta
113
+ error(' multilogit: rows of beta and columns of x do not agree' )
114
+ end ;
115
+ if ncat ~= cbeta
116
+ error([' multilogit: number of columns in beta and categories in y do not agree. ' ...
117
+ ' check that y is numbered continuously, i.e., y takes values in {0,1,2,3,4,5}' ...
118
+ ' is ok, y takes values in {0,1,2,3,4,99} is not.' ])
119
+ end ;
120
+
121
+ % ----------------------------------------------------%
122
+ % MAXIMUM LIKELIHOOD ESTIMATION OF MULTINOMIAL LOGIT %
123
+ % ----------------------------------------------------%
124
+
125
+ % likelihood and derivatives at starting values
126
+ [P ,lnL ] = multilogit_lik(y ,x ,beta ,d );
127
+ [g H ] = multilogit_deriv(x ,d ,P ,nvar ,ncat ,nobs );
128
+
129
+ iter= 0 ;
130
+
131
+ for j = 1 : ncat % vectorize beta and gradient for newton-raphson update
132
+ f = (j - 1 )*nvar + 1 ;
133
+ l = j * nvar ;
134
+ vb(f : l ,1 ) = beta(: ,j );
135
+ vg(f : l ,1 ) = g(: ,j );
136
+ end ;
137
+
138
+ % newton-raphson update
139
+ while (abs(vg ' *(H \ vg )/length(vg )) > tol ) & (iter < maxit )
140
+ iter = iter + 1 ;
141
+ betaold = beta ;
142
+ vbold = vb ;
143
+ vb = vbold - H \ vg ;
144
+ for j = 1 : ncat % de-vectorize updated beta for pass to multilogit_lik
145
+ f = (j - 1 )*nvar + 1 ;
146
+ l = j * nvar ;
147
+ beta(: ,j ) = vb(f : l ,1 );
148
+ end ;
149
+ [P ,lnL ] = multilogit_lik(y ,x ,beta ,d ); % update P, lnL
150
+ [g H ] = multilogit_deriv(x ,d ,P ,nvar ,ncat ,nobs ); % update g,H
151
+ for j = 1 : ncat ; % vectorize updated g for next N-R update
152
+ f = (j - 1 )*nvar + 1 ;
153
+ l = j * nvar ;
154
+ vg(f : l ,1 ) = g(: ,j );
155
+ end ;
156
+ disp([' iteration: ' num2str(iter )]);
157
+ disp([' log-likelihood: ' num2str(lnL )]);
158
+ end ;
159
+
160
+ % ---------------------------------------------------------%
161
+ % GENERATE RESULTS STRUCTURE %
162
+ % ---------------------------------------------------------%
163
+
164
+ results.meth = ' multilogit' ;
165
+ for j = 1 : ncat
166
+ results .beta_mat(: ,j ) = beta(: ,j ) ./ xstd ' ; % restore original scale
167
+ end ;
168
+ for j = 1 : ncat
169
+ f = (j - 1 )*nvar + 1 ;
170
+ l = j * nvar ;
171
+ results .beta_vec(f : l ,1 ) = results .beta_mat(: ,j );
172
+ end ;
173
+ results.covb = - inv(H )./kron(ones(ncat ),(xstd ' *xstd )); % restore original scale
174
+ stdb = sqrt(diag(results .covb ));
175
+ results.tstat_vec = results .beta_vec ./ stdb ;
176
+ for j = 1 : ncat
177
+ f = (j - 1 )*nvar + 1 ;
178
+ l = j * nvar ;
179
+ results .tstat_mat(: ,j ) = results .tstat_vec(f : l ,1 );
180
+ end ;
181
+ P_0 = ones(nobs ,1 ) - sum(P ' )' ;
182
+ results.yfit = [P_0 P ];
183
+ results.lik = lnL ;
184
+ results.cnvg = tol ;
185
+ results.iter = iter ;
186
+ results.nobs = nobs ;
187
+ results.nvar = nvar ;
188
+ results.ncat = ncat ;
189
+ results.count = [nobs - sum(sum(d )' ) sum(d )];
190
+ results.y = y ;
191
+
192
+ % basic specification testing;
193
+ p = results .count / nobs ;
194
+ lnLr = nobs * sum((p .* log(p ))' ); % restricted log-likelihood: intercepts only
195
+ results.lratio = - 2 *(lnLr - results .lik );
196
+ results.rsqr = 1 - (results .lik / lnLr ); % McFadden pseudo-R^2
197
+
198
+
199
+
200
+
201
+ % ---------------------------------------------------------%
202
+ % SUPPLEMENTARY FUNCTION FOR COMPUTING DERIVATIVES %
203
+ % ---------------------------------------------------------%
204
+
205
+ function [g ,H ] = multilogit_deriv(x ,d ,P ,nvar ,ncat ,nobs );
206
+ % PURPOSE: Computes gradient and Hessian of multinomial logit
207
+ % model
208
+ % ---------------------------------------------------------
209
+ % References: Greene (1997), p.914
210
+
211
+ % written by:
212
+ % Simon D. Woodcock
213
+ % CISER / Economics
214
+ % 201 Caldwell Hall
215
+ % Cornell University
216
+ % Ithaca, NY 14850
217
+ % sdw9@cornell.edu
218
+
219
+ % compute gradient matrix (nvar x ncat)
220
+ tmp = d - P ;
221
+ g = x ' *tmp ;
222
+
223
+ % compute Hessian, which has (ncat)^2 blocks of size (nvar x nvar)
224
+ % this algorithm builds each block individually, m&n are block indices
225
+ H = zeros(nvar * ncat );
226
+ for m = 1 : ncat ;
227
+ for n = 1 : ncat ;
228
+ fr = (m - 1 )*nvar + 1 ;
229
+ lr = m * nvar ;
230
+ fc = (n - 1 )*nvar + 1 ;
231
+ lc = n * nvar ;
232
+ index = (n == m );
233
+ index = repmat(index ,nobs ,1 );
234
+ H(fr : lr ,fc : lc ) = -( ( x .*( P(: ,m )*ones(1 ,nvar ) ) )' * ( x .*( (index - P(: ,n ))*ones(1 ,nvar ) ) ) ) ;
235
+ end ;
236
+ end ;
0 commit comments