-
Notifications
You must be signed in to change notification settings - Fork 8
/
bootstrap_var.m
213 lines (191 loc) · 7.04 KB
/
bootstrap_var.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
function [outpars,LL] = ...
bootstrap_var(pars,T,B,opts,control,equal,fixed,scale,parallel,match)
%-------------------------------------------------------------------------%
%
% Title: Parametric bootstrap in regime-switching state-space models
% (switching vector autoregressive model)
%
% Purpose: BOOTSTRAP_VAR performs parametric bootstrap of the maximum
% likelihood estimator (MLE) in the switching vector
% autoregresssive (VAR) model
% x(t) = A(1,S(t)) x(t-1) + ... + A(p,S(t)) x(t-p) + v(t,S(t))
% where x(t) is the observed measurement vector, S(t) is a latent
% variable indicating the current (unobserved) regime, and
% v(t,S(t)) is a noise term.
%
% Usage: [outpars,LL] = bootstrap_var(pars,T,B,opts,control,equal,...
% fixed,scale,parallel,match)
%
% Inputs: pars - structure of estimated model parameters with fields 'A',
% 'Q','mu','Sigma','Pi', and 'Z'. Typically, this
% structure is obtaining by calling init_var, switch_var,
% fast_var, or reestimate_var
% T - Time series length
% B - Number of bootstrap replicates (default = 500)
% control - optional struct variable with fields:
% eps tolerance for EM termination; default = 1e-8
% 'init': starting point for EM algorithm
% 'ItrNo': number of EM iterations; default = 100
% 'beta0': initial inverse temperature parameter for
% deterministic annealing; default = 1
% 'betarate': decay rate for temperature; default = 1
% 'safe': if true, regularizes variance matrices in
% switching Kalman filtering to be well-conditioned
% before inversion. If false, no regularization (faster
% but less safe)
% 'abstol': absolute tolerance for eigenvalues before
% inversion of covariance matrices (eigenvalues less
% than abstol are set to this value)
% 'reltol': relative tolerance for eigenvalues before
% inversion of covariance matrices (eigenvalues less
% than (reltol * largest eigenvalue) are set to this
% value)
% equal - optional structure with fields:
% 'A': if true, estimates of transition matrices A(l,j)
% are equal across regimes j=1,...,M. Default = false
% 'Q': if true, estimates of innovation matrices Q(j) are
% equal across regimes. Default = false
% 'mu': if true, estimates of initial mean state vectors
% mu(j) are equal across regimes. Default = true
% 'Sigma': if true, estimates of initial variance matrices
% Sigma(j) are equal across regimes. Default = true
% fixed - optional struct variable with fields 'A','Q','mu',
% 'Sigma', 'Pi', 'Z'. If not empty, each field must be an
% array of the same dimension as the parameter. Numeric
% values in the array are interpreted as fixed coefficients
% whereas NaN's represent free (unconstrained) coefficients.
% scale - optional structure with field:
% 'A': upper bound on norm of eigenvalues of A matrices.
% Must be in (0,1) to guarantee stationarity of state
% process.
% match - parameter to use to match the bootstrap replicates to
% the maximum likelihood estimate across regimes: 'A',
% 'AQ', 'COV', 'COR', or 'no' for no matching (not recommended)
%
%
% Outputs: outpars - struct with fields
% 'A': Bootstrap distribution of A (size rxrxpxMxB)
% 'Q': Bootstrap distribution of Q (size rxrxMxB)
% 'mu': Bootstrap distribution of mu (size rxMxB)
% 'Sigma': Bootstrap distribution of Sigma (size rxrxMxB)
% 'Pi': Bootstrap distribution of Pi (size MxB)
% 'Z': Bootstrap distribution of Z (size MxMxB)
% LL - Bootstrap distribution of attained log-likelihood (1xB)
%
%
% Author: David Degras, University of Massachusetts Boston
%
%-------------------------------------------------------------------------%
% Check number of arguments
narginchk(3,10);
% Initialize missing arguments if needed
if ~exist('B','var')
B = 500;
end
if ~exist('control','var') || ~isstruct(control)
control = struct('verbose',false);
end
if isfield(control,'verbose')
verbose = control.verbose;
else
verbose = false;
end
if ~exist('equal','var')
equal = [];
end
if ~exist('fixed','var')
fixed = [];
end
if ~exist('scale','var')
scale = [];
end
if ~exist('opts','var')
opts = [];
end
if ~exist('parallel','var') || isempty(parallel)
parallel = true;
end
if ~exist('match','var') || isempty(match)
match = 'COV';
end
assert(ismember(match,{'A','AQ','COV','COR','no'}))
% Model dimensions
[r,~,p,M] = size(pars.A);
% Bootstrap estimates
Aboot = zeros(r,r,p,M,B);
Qboot = zeros(r,r,M,B);
muboot = zeros(r,M,B);
Sigmaboot = zeros(r,r,M,B);
Piboot = zeros(M,B);
Zboot = zeros(M,M,B);
LLboot = zeros(1,B);
warning('off');
% Set up parallel pool if needed
if parallel
pool = gcp('nocreate');
if isempty(pool)
pool = gcp;
end
poolsize = pool.NumWorkers;
control.verbose = false;
else
poolsize = 0;
end
% Initialize progress bar if required
if verbose && parallel
parfor_progress(B);
end
% Set starting value for EM algorithm if provided
pars0 = [];
if isfield(control,'init')
pars0 = control.init;
end
parfor (b=1:B, poolsize)
% Resample data by parametric bootstrap
% Ensure that each regime occurs at least once
count = 0; Meff = 0;
y = [];
while count < 20 && Meff < M
count = count + 1;
[y,S] = simulate_var(pars,T);
Meff = numel(unique(S));
end
% Run EM algorithm
pars0b = pars0;
if isempty(pars0b)
try
pars0b = init_var(y,M,p,opts,control,equal,fixed,scale);
catch
continue
end
end
try
[~,~,~,~,parsboot,LL] = ...
switch_var(y,M,p,pars0b,control,equal,fixed,scale);
catch
continue
end
% Store results
Aboot(:,:,:,:,b) = parsboot.A;
Qboot(:,:,:,b) = parsboot.Q;
muboot(:,:,b) = parsboot.mu;
Sigmaboot(:,:,:,b) = parsboot.Sigma;
Piboot(:,b) = parsboot.Pi;
Zboot(:,:,b) = parsboot.Z;
LLboot(b) = max(LL);
% Display progress if required
if verbose && parallel
parfor_progress;
end
end
outpars = struct('A',Aboot, 'Q',Qboot, 'mu',muboot, 'Sigma',Sigmaboot, ...
'Pi',Piboot, 'Z',Zboot);
LL = LLboot;
% Match bootstrap replicates to MLE
if ~strcmp(match,'no')
outpars = bootstrap_match(outpars,pars,match);
end
if verbose && parallel
parfor_progress(0);
end
end