-
Notifications
You must be signed in to change notification settings - Fork 2
/
mhtmle2.m
315 lines (293 loc) · 10.4 KB
/
mhtmle2.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
function [par_out,stde_out,llh_out,opt_out] = mhtmle(y,M,cens,x,unobs_form,shock_form,nrunobs,nrshocks)
% ////////////////////////////////////////////////////////////////////////
% Maximum likelihood estimation of MHT model using numerical inversion of
% the laplace transform
%
% Author: Tim Salimans (minor adaptations by Jaap Abbring)
%
% INPUT:
% - y, n x 1 double or integer vector of observations
% - cens, n x 1 logical vector of scalar indicating whether the
% observations are censored (1 for censoring, 0 not)
% - x, n x k double matrix of explanatory variables
% - unobs_form, string indicating the distribution of the unobservables
% currently supports 'point' and 'gamma'
% - shock_form, string indicating the distribution of the shocks
% currently supports 'point' and 'gamma'
% - nrunobs, scalar indicating the number of unobservables
% only used for pointwise unobservables
% - nrshocks, scalar indicating the number of shocks
% only used for pointwise shocks
%
% OUTPUT:
% - par_out, structure of estimated parameters
% - stde_out, structure containing the asymptotic standard errors
% - llh_out, scalar containing the maximum log likelihood value
% - opt_out, structure containing information on the optimization
%
% Information on convergence is displayed on screen.
%
% ////////////////////////////////////////////////////////////////////////
% choose alternative information matrix estimator
altim = 'fd'; % 'fd': Hessian calculated using finite diff analyt score
% 'op': OPG estimator
% default: Hessian outputted by fminunc (BFGS)
% check input
if size(y,1)<size(y,2);
y=y';
end
if size(x,1)<size(x,2);
x=x';
end
if size(cens,1)<size(cens,2);
cens=cens';
end
n=length(y);
k=size(x,2);
if ~all(size(y)==[n 1])
error('input y has the wrong size')
end
if ~all(size(x)==[n k])
error('input x has the wrong size')
end
cens=logical(cens);
if length(cens)==1
cens=(ones(n,1)*cens>0);
end
if ~all(size(cens)==[n 1])
error('input cens has the wrong size')
end
if nargin<7
if nargin<5
error('too few input arguments')
elseif nargin==5
nrunobs=1;
nrshocks=1;
else
if isequal(unobs_form,'gamma')&&isequal(shock_form,'point')
nrshocks=nrunobs;
nrunobs=1;
elseif isequal(unobs_form,'point')&&isequal(shock_form,'gamma')
nrshocks=1;
else
error('too few input arguments')
end
end
end
% initialize
llh=[];
iter=0;
maxllh=-Inf;
pd=false;
% maximize likelihood with random starting points to find global optimum
while (length(llh)<3 || sum(llh>max(llh)-(1e-3)*n)<3 || ~pd) && iter<10
% new iteration
iter=iter+1;
disp(['Maximizing log likelihood, random initialization ' int2str(iter)]);
% parameter initialization
% scale of data
mm=mean(y);
% set starting values
var=log(mm^2*mean(1./y-1/mm))+randn/10;
if isequal(unobs_form,'point')
v=log(ones(nrunobs,1)*mm)+randn(nrunobs,1)/2;
p=ones(nrunobs-1,1);
elseif isequal(unobs_form,'gamma')
if nrunobs>1
error('nrunobs should be 1 for gamma specification')
end
v=randn/2;
p=randn/2-log(mm);
else
error('wrong distribution for unobservables')
end
k=size(x,2);
if k==0
beta=[];
else
beta=zeros(size(x,2),1);
end
if isequal(shock_form,'point')
nu=log(mm)-log(4:1:3+nrshocks)'+randn(nrshocks,1)/2;
lambda=-log(mm)*ones(nrshocks,1);
elseif isequal(shock_form,'gamma')
if nrshocks>1
error('nrshocks should be 1 for gamma specification')
end
lambda=-log(mm);
nu=[randn/2; randn/2];
else
error('wrong distribution for shocks')
end
% convert to parameter vector of startvalues
startvalues=[var; p; v; lambda; nu; beta];
% estimation
options=optimset('GradObj','on','LargeScale','off','HessUpdate','bfgs','Display','off','MaxIter',1000);
eval(['[estpar,nllh,eflag,output,grad,hessian]=fminunc(@(par)mhtobj2(@'...
unobs_form shock_form ',par,y,M,cens,x,nrunobs,nrshocks),startvalues,options);']);
% check and save results
if eflag>0
llh=[llh -nllh];
if -nllh>maxllh
maxllh=-nllh;
par=estpar;
mlehess=hessian;
optinf=output;
% check positive definiteness of hessian
try
pd=all(diag(chol(mlehess))>0);
catch
pd=false;
end
end
end
end
% examine results
if ~isfinite(maxllh)
error('All optimization attempts failed, check the model specification.')
elseif iter==10
disp('Solution might be a local optimum!')
disp('Try using a simpler specification.')
else
disp('Optimization was successful!')
end
if ~pd
disp('Hessian at optimum was not positive definite, so standard errors are inaccurate.')
end
% retrieve parameters
par_out=struct;
par_out.bm_var=exp(par(1));
if isequal(unobs_form,'point')
par_out.unobs_p=exp([1; par(2:nrunobs)])';
par_out.unobs_p=par_out.unobs_p/sum(par_out.unobs_p);
par_out.unobs_v=exp(par(nrunobs+1:2*nrunobs))';
if nrshocks>0
if isequal(shock_form,'point')
par_out.shock_lambda=exp(par(2*nrunobs+1:2*nrunobs+nrshocks))';
par_out.shock_nu=-exp(par(2*nrunobs+nrshocks+1:2*nrunobs+2*nrshocks))';
shockind=(2*nrunobs+1:2*nrunobs+2*nrshocks);
else
par_out.shock_lambda=exp(par(2*nrunobs+1));
par_out.shock_nu=exp(par(2*nrunobs+2));
par_out.shock_rho=exp(par(2*nrunobs+3));
shockind=(2*nrunobs+1:2*nrunobs+3);
end
end
else
par_out.unobs_omega=exp(par(2));
par_out.unobs_tau=exp(par(3));
if nrshocks>0
if isequal(shock_form,'point')
par_out.shock_lambda=exp(par(4:3+nrshocks))';
par_out.shock_nu=-exp(par(4+nrshocks:3+2*nrshocks))';
shockind=(4:3+2*nrshocks);
else
par_out.shock_lambda=exp(par(4));
par_out.shock_nu=exp(par(5));
par_out.shock_rho=exp(par(6));
shockind=(4:6);
end
end
end
par_out.beta=par(end-k+1:end)';
% alternative IM estimates
if isequal(altim,'fd')
disp('Using finite differences of analytical score to estimate information matrix!')
eval(['mlehess=numjac(@(dpar)mhtgrad2(@'...
unobs_form shock_form ',dpar,y,M,cens,x,nrunobs,nrshocks),par);']);
mlehess=0.5*mlehess+0.5*mlehess';
elseif isequal(altim,'op')
disp('Using OPG estimator of information matrix!')
eval(['[opprobs,opgrad]=numinvlap2(@'...
unobs_form shock_form ',par,y,M,cens,x,nrunobs,nrshocks);']);
opgrad=-opgrad.*(1./opprobs);
mlehess = opgrad'*opgrad;
end
% retieve asymptotic standard errors using delta rule
if nargout>=2
% check whether all shock-parameters are identified
if nrshocks>0
if isequal(shock_form,'point')
shockscale=-par_out.shock_lambda.*par_out.shock_nu;
else
shockscale=par_out.shock_lambda*par_out.shock_rho/par_out.shock_nu;
end
if all(shockscale>0.05)
shocknotid=false;
mlevar=inv(mlehess);
else
shocknotid=true;
ind=1:length(par);
ind(shockind)=[];
mlevar=zeros(length(par),length(par));
mlevar(ind,ind)=inv(mlehess(ind,ind));
end
else
shocknotid=false;
mlevar=inv(mlehess);
end
% get standard errors
stde_out=struct;
stde_out.bm_var=par_out.bm_var*sqrt(mlevar(1,1));
if isequal(unobs_form,'point')
gmat=[zeros(1,nrunobs-1); diag(par_out.unobs_p(2:end))]-par_out.unobs_p'*par_out.unobs_p(2:end);
stde_out.unobs_p=sqrt(diag(gmat*mlevar(2:nrunobs,2:nrunobs)*gmat'))';
stde_out.unobs_v=par_out.unobs_v.*sqrt(diag(mlevar(nrunobs+1:2*nrunobs,nrunobs+1:2*nrunobs)))';
if nrshocks>0
if isequal(shock_form,'point')
if shocknotid
stde_out.shock_lambda='not identified';
stde_out.shock_nu='not identified';
else
stde_out.shock_lambda=par_out.shock_lambda.*...
sqrt(diag(mlevar(2*nrunobs+1:2*nrunobs+nrshocks,2*nrunobs+1:2*nrunobs+nrshocks)))';
stde_out.shock_nu=-par_out.shock_nu.*...
sqrt(diag(mlevar(2*nrunobs+nrshocks+1:2*nrunobs+2*nrshocks,2*nrunobs+nrshocks+1:2*nrunobs+2*nrshocks)))';
end
else
if shocknotid
stde_out.shock_lambda='not identified';
stde_out.shock_nu='not identified';
stde_out.shock_rho='not identified';
else
stde_out.shock_lambda=par_out.shock_lambda*sqrt(mlevar(2*nrunobs+1,2*nrunobs+1));
stde_out.shock_nu=par_out.shock_nu*sqrt(mlevar(2*nrunobs+2,2*nrunobs+2));
stde_out.shock_rho=par_out.shock_rho*sqrt(mlevar(2*nrunobs+3,2*nrunobs+3));
end
end
end
else
stde_out.unobs_omega=par_out.unobs_omega*sqrt(mlevar(2,2));
stde_out.unobs_tau=par_out.unobs_tau*sqrt(mlevar(3,3));
if nrshocks>0
if isequal(shock_form,'point')
if shocknotid
stde_out.shock_lambda='not identified';
stde_out.shock_nu='not identified';
else
stde_out.shock_lambda=par_out.shock_lambda.*sqrt(diag(mlevar(4:3+nrshocks,4:3+nrshocks)))';
stde_out.shock_nu=-par_out.shock_nu.*sqrt(diag(mlevar(4+nrshocks:3+2*nrshocks,4+nrshocks:3+2*nrshocks)))';
end
else
if shocknotid
stde_out.shock_lambda='not identified';
stde_out.shock_nu='not identified';
stde_out.shock_rho='not identified';
else
stde_out.shock_lambda=par_out.shock_lambda*sqrt(mlevar(4,4));
stde_out.shock_nu=par_out.shock_nu*sqrt(mlevar(5,5));
stde_out.shock_rho=par_out.shock_rho*sqrt(mlevar(6,6));
end
end
end
end
stde_out.beta=sqrt(diag(mlevar(end-k+1:end,end-k+1:end)))';
end
% final log likelihood
if nargout>=3
llh_out=maxllh;
end
% optimization information
if nargout==4
opt_out=optinf;
end