-
Notifications
You must be signed in to change notification settings - Fork 6
/
DiagnosticsShadowrate.m
308 lines (269 loc) · 9.19 KB
/
DiagnosticsShadowrate.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
function PSRFi = DiagnosticsShadowrate(shadowrateDraws,n)
% for i=1:T
% display('--------------------------');
% display(['shadowrate obs.' num2str(i)]);
% PSRFi(i)=mean(psrf(shadowrateDraws(:,i))); %#ok<AGROW>
% display(['Average PSRF ' num2str(PSRFi(i)) ]);
% IFi(i,:)=ineff(shadowrateDraws(:,i)); %#ok<AGROW>
% display(['Average IF (4% 8% 15% tapering) ' num2str(IFi(i,:)) ]);
% end
[MCMCdraws,Ns,elbObs] = size(shadowrateDraws); %#ok<ASGLU>
if Ns > 1
error('better call for each shadowrate separately')
end
theseDraws = squeeze(shadowrateDraws);
PSRFi=mean(psrf(theseDraws));
IFi=mean(ineff(theseDraws));
% summary
if nargout == 0
display('--------------------------'); %#ok<DISPLAYPROG>
display(sprintf('shadowrate %d', n)); %#ok<DSPS>
display(['Average PSRF ' num2str(PSRFi) ]);
display(['Average IF (4% 8% 15% tapering) ' num2str(IFi) ]);
end
function [R,neff,V,W,B] = psrf(varargin)
%PSRF Potential Scale Reduction Factor
%
% [R,NEFF,V,W,B] = PSRF(X) or
% [R,NEFF,V,W,B] = PSRF(x1,x2,...,xs)
% returns "Potential Scale Reduction Factor" (PSRF) for
% collection of MCMC-simulations. X is a NxDxM matrix
% which contains M MCMC simulations of length N, each with
% dimension D. MCMC-simulations can be given as separate
% arguments x1,x2,... which should have the same length.
%
% Returns
% R PSRF in a row vector of length D
% neff estimated effective number of samples M*N*V/B
% V estimated mixture-of-sequences variances
% W estimated within sequence variances
% B estimated between sequence variances
%
% The idea of the PSRF is that if R is not near 1 (below 1.1 for
% example) one may conclude that the tested samples were not from
% the same distribution (chain might not have been converged
% yet).
%
% If only one simulation is given, the factor is calculated
% between first and last third of the chain. Note that use of
% only one chain will produce over-optimistic result.
%
% Method is from:
% Brooks, S.P. and Gelman, A. (1998) General methods for
% monitoring convergence of iterative simulations. Journal of
% Computational and Graphical Statistics. 7, 434-455. Note that
% this function returns square-root definiton of R (see Gelman
% et al (2003), Bayesian Data Analsyis p. 297).
%
% See also
% CPSRF, MPSRF, IPSRF
% Copyright (C) 1999 Simo Saerkkae
% Copyright (C) 2003 Aki Vehtari
%
% This software is distributed under the GNU General Public
% Licence (version 2 or later); please refer to the file
% Licence.txt, included with the software, for details.
% 2004-01-22 Aki.Vehtari@hut.fi Added neff, R^2->R, and cleaning
% In case of one argument split to two halves (first and last thirds)
onechain=0;
if nargin==1
X = varargin{1};
if size(X,3)==1
n = floor(size(X,1)/3);
x = zeros([n size(X,2) 2]);
x(:,:,1) = X(1:n,:);
x(:,:,2) = X((end-n+1):end,:);
X = x;
onechain=1;
end
elseif nargin==0
error('Cannot calculate PSRF of scalar');
else
X = zeros([size(varargin{1}) nargin]);
for i=1:nargin
X(:,:,i) = varargin{i};
end
end
[N,D,M]=size(X);
if N<1
error('Too few samples');
end
% Calculate means W of the variances
W = zeros(1,D);
for n=1:M
x = X(:,:,n) - repmat(mean(X(:,:,n)),N,1);
W = W + sum(x.*x);
end
W = W / ((N-1) * M);
% Calculate variances B (in fact B/n) of the means.
Bpn = zeros(1,D);
m = mean(reshape(mean(X),D,M)');
for n=1:M
x = mean(X(:,:,n)) - m;
Bpn = Bpn + x.*x;
end
Bpn = Bpn / (M-1);
% Calculate reduction factors
S = (N-1)/N * W + Bpn;
R = (M+1)/M * S ./ W - (N-1)/M/N;
V = R .* W;
R = sqrt(R);
B = Bpn*N;
neff = min(M*N*V./B,M*N);
if onechain && (nargout>1)
neff=neff*3/2;
end
function if_=ineff(betas)
gew=momentg(betas);
if_=zeros(size(betas,2),1);
for i=1:size(betas,2); if_(i,1)=1./(gew(i).rne1); if_(i,2)=1./(gew(i).rne2); if_(i,3)=1./(gew(i).rne3); end
function results = momentg(draws)
% PURPOSE: computes Gewke's convergence diagnostics NSE and RNE
% (numerical std error and relative numerical efficiencies)
% -----------------------------------------------------------------
% USAGE: result = momentg(draws)
% where: draws = a matrix of Gibbs draws (ndraws x nvars)
% -----------------------------------------------------------------
% RETURNS: a structure result:
% result.meth = 'momentg'
% result.ndraw = # of draws
% result.nvar = # of variables
% result(i).pmean = posterior mean for variable i
% result(i).pstd = posterior std deviation
% result(i).nse = nse assuming no serial correlation for variable i
% result(i).rne = rne assuming no serial correlation for variable i
% result(i).nse1 = nse using 4% autocovariance tapered estimate
% result(i).rne1 = rne using 4% autocovariance taper
% result(i).nse2 = nse using 8% autocovariance taper
% result(i).rne2 = rne using 8% autocovariance taper
% result(i).nse3 = nse using 15% autocovariance taper
% result(i).rne3 = rne using 15% autocovariance taper
% -----------------------------------------------------------------
% SEE ALSO: coda(), apm()
% -----------------------------------------------------------------
% REFERENCES: Geweke (1992), `Evaluating the accuracy of sampling-based
% approaches to the calculation of posterior moments', in J.O. Berger,
% J.M. Bernardo, A.P. Dawid, and A.F.M. Smith (eds.) Proceedings of
% the Fourth Valencia International Meeting on Bayesian Statistics,
% pp. 169-194, Oxford University Press
% Also: `Using simulation methods for Bayesian econometric models:
% Inference, development and communication', at: www.econ.umn.edu/~bacc
% -----------------------------------------------------------------
% written by:
% James P. LeSage, Dept of Economics
% University of Toledo
% 2801 W. Bancroft St,
% Toledo, OH 43606
% jpl@jpl.econ.utoledo.edu
% NOTE: this code draws heavily on MATLAB programs written by
% Siddartha Chib available at: www.econ.umn.edu/~bacc
% I have repackaged it to make it easier to use.
[ndraw, nvar] = size(draws);
results.ndraw = ndraw;
results.meth = 'momentg';
results.nvar = nvar;
NG=100;
if ndraw < NG
error('momentg: needs a larger number of ndraws');
end;
ntaper=[4 8 15];
ns = floor(ndraw/NG);
nuse = ns*NG;
for jf = 1:nvar; % loop over all variables
cnt = 0;
cn = zeros(NG);
cd = zeros(NG);
cdn = zeros(NG);
cdd = zeros(NG);
cnn = zeros(NG);
cvar = zeros(NG);
% form sufficiency statistics needed below
td=0; tn=0; tdd=0; tnn=0; tdn=0; tvar=0;
for ig=1:NG;
gd=0; gn=0; gdd=0; gdn=0; gnn=0; gvar=0;
for is = 1:ns;
cnt = cnt + 1;
g = draws(cnt,jf);
ad = 1;
an = ad*g;
gd = gd+ad;
gn = gn+an;
gdn = gdn + ad*an;
gdd = gdd + ad*ad;
gnn = gnn + an*an;
gvar = gvar + an*g;
end; % end of for is
td = td+gd;
tn = tn+gn;
tdn = tdn+gdn;
tdd = tdd+gdd;
tnn=tnn+gnn;
tvar=tvar+gvar;
cn(ig)=gn/ns;
cd(ig)=gd/ns;
cdn(ig)=gdn/ns;
cdd(ig)=gdd/ns;
cnn(ig)=gnn/ns;
cvar(ig)=gvar/ns;
end; %for ig
eg = tn/td;
varg = tvar/td - eg^2;
sdg = -1;
if (varg>0); sdg=sqrt(varg); end;
% save posterior means and std deviations to results structure
results(jf).pmean = eg;
results(jf).pstd = sdg;
% numerical standard error assuming no serial correlation
varnum=(tnn-2*eg*tdn+tdd*eg^2)/(td^2);
sdnum=-1; if (varnum>0); sdnum=sqrt(varnum); end;
% save to results structure
results(jf).nse = sdnum;
results(jf).rne = varg/(nuse*varnum);
%get autocovariance of grouped means
barn=tn/nuse;
bard=td/nuse;
for ig=1:NG;
cn(ig)=cn(ig)-barn;
cd(ig)=cd(ig)-bard;
end;
for lag=0:NG-1;
ann=0; add=0; and=0; adn=0;
for ig=lag+1:NG;
ann=ann+cn(ig)*cn(ig-lag);
add=add+cd(ig)*cd(ig-lag);
and=and+cn(ig)*cd(ig-lag);
adn=adn+cd(ig)*cd(ig-lag);
end; %ig
% index 0 not allowed, lag+1 stands for lag
rnn(lag+1)=ann/NG;
rdd(lag+1)=add/NG;
rnd(lag+1)=and/NG;
rdn(lag+1)=adn/NG;
end; %lag
% numerical standard error with tapered autocovariance functions
for mm=1:3;
m=ntaper(mm);
am=m;
snn=rnn(1); sdd=rdd(1); snd=rnd(1);
for lag=1:m-1;
att=1-lag/am;
snn=snn+2*att*rnn(lag+1);
sdd=sdd+2*att*rdd(lag+1);
snd=snd+att*(rnd(lag+1) + rnd(lag+1));
end; %lag
varnum=ns*nuse*(snn-2*eg*snd+sdd*eg^2)/(td^2);
sdnum=-1;
if (varnum>0); sdnum=sqrt(varnum); end;
% save results in structure
if mm == 1
results(jf).nse1 = sdnum;
results(jf).rne1 = varg/(nuse*varnum);
elseif mm == 2
results(jf).nse2 = sdnum;
results(jf).rne2 = varg/(nuse*varnum);
elseif mm == 3
results(jf).nse3 = sdnum;
results(jf).rne3 = varg/(nuse*varnum);
end;
end; % end of for mm loop
end; % end of loop over variables