-
Notifications
You must be signed in to change notification settings - Fork 18
/
invert_monte_carlo.m
107 lines (89 loc) · 3.91 KB
/
invert_monte_carlo.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
function [posterior, logEvidence, theta]= monte_carlo (data, prior)
% Bayesian logistic regression using MCMC/sampling (Metropolis Hasting)
% -------------------------------------------------------------------------
% This script implements a Metropolis-Hastings algorithm to generate samples
% from the posterior of our logisitic problem.
% We also compute the so-called harmonic estimator of the model evidence
% using the posterior samples.
% -------------------------------------------------------------------------
%% Metropolis-Hastings algorithm
% ========================================================================
% Here, we use a Markov Chain to generate samples and an accept/reject rule
% based on the joint density to collect samples from the posterior.
% Initialisation
% ---------------------------------------------------------------------
% number of samples
N = 1e6;
% variance of the proposal distribution
proposal_sigma = 0.15;
% starting values
theta = 0;
old = log_joint(data, prior, theta);
% Main loop
% ---------------------------------------------------------------------
for t = 2 : N
% propose a new sample with a random step (Markov-Chain jump)
proposal = theta(t-1) + sqrt (proposal_sigma) * randn();
% compute the (log) joint probability of the proposal
new = log_joint (data, prior, proposal);
% do we get warmer?
accept_prob = exp (new - old);
accept = accept_prob > rand(1) ;
if accept % if yes, confirm the jump
theta(t) = proposal;
old = new;
else % otherwise, stay in place
theta(t) = theta(t-1);
end
end
%% Posterior characterization
% ========================================================================
% Before we can use the law of large numbers, we need to clean up the
% samples to ensure they are memory less (no effect of the starting point)
% and independent (no autocorrelation).
% If we were doing things properly, we would have run multiple chains and
% would compute convergence scores, eg. Gelman Rubin Disagnostic...
% Remove "burn in" phase. See "Geweke diagnostic"
% ---------------------------------------------------------------------
theta(1:100) = [];
% De-correlation
% ---------------------------------------------------------------------
% Compute autocorrelation for increasing lag
for lag = 1 : 100
AR(lag) = corr(theta(lag+1:end)', theta(1:end-lag)');
end
% find minimum lag to have negligible autocorrelation
optlag = find(AR<.05, 1);
% decimate the samples accordingly
theta = theta(1:optlag:end);
% Posterior moments
% ---------------------------------------------------------------------
% We can now use the law of large numbers to approximate the sufficient
% statistics of the posterior distribution.
posterior.mu = mean (theta);
posterior.sigma = var (theta);
%% Model evidence
% ========================================================================
% If one can approximate the model evidence using samples from the prior,
% it is better to do it using samples from the posterior because it better
% explores where the likelihood is high. Here, we apply the so-called Harmonic
% estimator which uses samples from the posterior: \theta_t ~ p(\theta|y)
%
% $$ p(y) \approx N / sum [1 / p(y|\theta_t)] $$
%
% Note that this estimator tend to overestimate the evidence and is quite
% insensitive to the prior:
% See https://radfordneal.wordpress.com/2008/08/17/the-harmonic-mean-of-the-likelihood-worst-monte-carlo-method-ever/
% Better (but slightly more complicated) estimators exists,like the one in
% Chib & Jeliazkov for the Metropolis-Hastings output.
for t = 1 : numel (theta)
ll(t) = log_likelihood (data, theta(t));
end
logEvidence = log (numel (ll)) - logsumexp (-ll);
end
% ========================================================================
% Returns log(sum(exp(a))) while avoiding numerical underflow.
function s = logsumexp(a)
ma = max(a);
s = ma + log(sum(exp(a - ma)));
end