-
Notifications
You must be signed in to change notification settings - Fork 3
/
spm_dcm_bpa.m
185 lines (157 loc) · 6.03 KB
/
spm_dcm_bpa.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
function [BPA] = spm_dcm_bpa(P,nocd)
% Produce an aggregate DCM using Bayesian parameter averaging
% FORMAT [BPA] = spm_dcm_bpa(DCM,nocd)
%
% DCM - {N [x M]} structure array of DCMs from N subjects
% ------------------------------------------------------------
% DCM{i}.M.pE - prior expectations of P parameters
% DCM{i}.M.pC - prior covariance
% DCM{i}.Ep - posterior expectations
% DCM{i}.Cp - posterior covariance
%
% nocd - optional flag for suppressing conditional dependencies.
% This is useful when evaluating the BPA of individual (contrasts
% of) parameters, where the BPA of a contrast should not be confused
% with the contrast of a BPA.
%
% BPA - DCM structure (array) containing Bayesian parameter averages
% ------------------------------------------------------------
% BPA.M.pE - prior expectations of P parameters
% BPA.M.pC - prior covariance
% BPA.Ep - posterior expectations
% BPA.Cp - posterior covariance
%
% BPA.Pp - posterior probability of > 0
% BPA.Vp - posterior variance
% BPA.... - other fields from DCM{1[,:]}
%__________________________________________________________________________
%
% This routine creates a new DCM in which the parameters are averaged over
% a number of fitted DCMs. These can be over sessions or over subjects.
% This average model can then be interrogated using the standard DCM
% 'review' options to look at contrasts of parameters. The resulting
% inferences correspond to a Bayesian Fixed Effects analysis. If called
% with no output arguments the Bayesian parameter average DCM will be
% written to DCM_BPA.mat; otherwise, the DCM structure is returned as BPA.
%
% If DCM is an {N x M} array, Bayesian parameter averaging will be
% applied to each model (i.e., each row) - and BPA becomes a {1 x M} cell
% array.
%
% See also spm_dcm_bma.m, spm_dcm_bmr.m and spm_dcm_peb.m
%__________________________________________________________________________
% Copyright (C) 2015 Wellcome Trust Centre for Neuroimaging
% Will Penny & Klaas Enno Stephan
% $Id: spm_dcm_bpa.m 7866 2020-05-30 09:57:38Z karl $
# SPDX-License-Identifier: GPL-2.0
% Preiminaries
%--------------------------------------------------------------------------
if nargin < 1
[P, sts] = spm_select([1 Inf],'^DCM.*\.mat$','Select DCM*.mat files');
if ~sts, return; end
end
if ischar(P), P = cellstr(P); end
% conditional dependencies option
%--------------------------------------------------------------------------
if nargin < 2, nocd = 0; end
% repeat for each column if P is and array
%--------------------------------------------------------------------------
if ~isvector(P)
% loop over models in each column
%----------------------------------------------------------------------
for i = 1:size(P,2)
BPA{i} = spm_dcm_bpa(P(:,i),nocd);
end
return
end
%-Loop through all selected models and get posterior means and precisions
%==========================================================================
N = numel(P);
TOL = exp(-16);
sEp = [];
Up = [];
Pp = [];
for i = 1:N
% get DCM structure
%----------------------------------------------------------------------
if ischar(P{i}), load(P{i}); else DCM = P{i}; end
% Only look at those parameters with non-zero prior variance
%----------------------------------------------------------------------
if isstruct(DCM.M.pC)
pC = diag(spm_vec(DCM.M.pC));
else
pC = DCM.M.pC;
end
j = diag(pC) > TOL & diag(pC) < 1/TOL;
pC = diag(j)*pC*diag(j);
% find the space spanned by the prior covariance
%----------------------------------------------------------------------
if i == 1
% suppress prior dependencies if necessary
%----------------------------------------------------------------------
if nocd, pC = diag(diag(pC)); end
U = spm_svd(pC,0);
j_first = j;
BPA = DCM;
else
if any(j ~= j_first)
error('DCMs must have same structure.');
end
end
% suppress posterior dependencies if necessary
%----------------------------------------------------------------------
Ep = spm_vec(DCM.Ep);
Cp = DCM.Cp;
if nocd, Cp = diag(diag(Cp)); end
% Get posterior precision matrix and mean
%----------------------------------------------------------------------
sEp(:,i) = Ep;
Up(:,i) = U'*Ep;
Cp = U'*Cp*U;
Pp(:,:,i) = inv(full(Cp));
end
%-Average models using Bayesian fixed-effects analysis -> average Ep,Cp
%==========================================================================
% average posterior covariance and mean
%--------------------------------------------------------------------------
Cp = inv(sum(Pp,3));
mEp = mean(sEp,2);
% average posterior mean
%--------------------------------------------------------------------------
Ep = 0;
for i = 1:N
Ep = Ep + Pp(:,:,i)*Up(:,i);
end
Ep = Cp*Ep;
% project back through U
%--------------------------------------------------------------------------
Cp = U*Cp*U';
Ep = U*Ep + mEp - U*(U'*mEp);
Ep = spm_unvec(Ep,DCM.M.pE);
%-Copy contents of first DCM into the output DCM and add BPA
%==========================================================================
BPA.averaged = true;
try
BPA.models = char(P);
end
% compute posterior probabilities and variance
%--------------------------------------------------------------------------
sw = warning('off','SPM:negativeVariance');
Vp = diag(Cp);
alpha = 0;
Pp = 1 - spm_Ncdf(0,abs(spm_vec(Ep) - alpha),Vp);
warning(sw);
BPA.Ep = Ep;
BPA.Cp = Cp;
BPA.Vp = spm_unvec(Vp,Ep);
BPA.Pp = spm_unvec(Pp,Ep);
%-Save new DCM if there are no output arguments
%==========================================================================
if nocd
BPA.name = 'BPA - no conditional dependencies';
else
BPA.name = 'Bayesian parameter average';
end
if ~nargout
save('DCM_BPA.mat', 'BPA', spm_get_defaults('mat.format'));
end