123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197 |
- function [DCM] = spm_dcm_average(P,name,nocond,graphics)
- % Produce an aggregate DCM model using Bayesian FFX averaging
- % FORMAT [DCM] = spm_dcm_average(P,name,nocond,graphics)
- %
- % P - character/cell array of DCM filenames
- % name - name of DCM output file (will be prefixed by 'DCM_avg_')
- % nocond - optional flag for suppressing conditional dependencies
- % graphics - optional flag for showing outliers (based on conditional
- % entropy)
- %
- % This routine creates a new DCM in which the parameters are averaged
- % over a number of fitted DCM models. 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
- % file, otherwise the DCM structure is returned.
- %
- % Note that the Bayesian averaging is only applied to the A, B and C
- % matrices (and matrix D if a nonlinear model is used).
- % All other quantities in the average model are initially simply copied from
- % the first DCM in the list. Subsequently, they are deleted before saving
- % the average DCM in order to avoid any false impression that averaged
- % models could be used for model comparison or contained averaged time series.
- % Neither operation is valid and will be prevented by the DCM interface.
- % Finally, note that only models with exactly the same A,B,C,(D) structure
- % and the same brain regions can be averaged.
- %
- % A Bayesian random effects analysis can be implemented for a particular
- % contrast using the spm_dcm_sessions.m function.
- %__________________________________________________________________________
- % Copyright (C) 2008 Wellcome Trust Centre for Neuroimaging
- % Will Penny & Klaas Enno Stephan
- % $Id: spm_dcm_average.m 7271 2018-03-04 13:11:54Z karl $
- % Preiminaries
- %--------------------------------------------------------------------------
- try
- P;
- catch
- [P, sts] = spm_select([1 Inf],'^DCM.*\.mat$','Select DCM*.mat files');
- if ~sts, return; end
- end
- if ischar(P), P = cellstr(P); end
- N = numel(P);
- % options and filename
- %--------------------------------------------------------------------------
- try, name; catch, name = spm_input('Name for DCM_avg_???.mat','+1','s'); end
- try, nocond; catch, nocond = 0; end
- try, graphics; catch, graphics = 0; end
- %-Loop through all selected models and get posterior means and precisions
- %==========================================================================
- for model = 1:N
-
- % get DCM structure
- %----------------------------------------------------------------------
- if ischar(P{model}), load(P{model}); else, DCM = P{model}; 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
- wsel = diag(pC) > 0 & diag(pC) < 128;
- pC = diag(wsel)*pC*diag(wsel);
- wsel = find(wsel);
-
- % find the space spanned by the prior covariance
- %----------------------------------------------------------------------
- if model == 1
-
- % suppress prior dependencies if necessary
- %----------------------------------------------------------------------
- if nocond, pC = diag(diag(pC)); end
-
- U = spm_svd(pC,0);
- wsel_first = wsel;
- DCM_first = DCM;
- else
- if length(wsel) ~= length(wsel_first) || any(wsel ~= wsel_first)
- error('DCMs must have same structure.');
- end
- end
-
- % suppress posterior dependencies if necessary
- %----------------------------------------------------------------------
- Cp = DCM.Cp;
- if nocond, Cp = diag(diag(Cp)); end
-
- % Get posterior precision matrix and mean
- %----------------------------------------------------------------------
- Cp = U'*Cp*U;
- Ep = U'*spm_vec(DCM.Ep);
- miCp(:,:,model) = inv(full(Cp));
- mEp(:,model) = Ep;
-
-
- % evaluate diagnostics
- %----------------------------------------------------------------------
- if graphics
- T(model) = trace(Cp);
- H(model) = spm_logdet(miCp(:,:,model));
- Fs(model) = DCM.F;
- end
-
- end
- %-Report free energies and conditional entropies
- %==========================================================================
- if graphics
- spm_figure('GetWin','BPA');
-
- subplot(3,1,1), bar(Fs)
- title('Free energy','FontSize',16)
- xlabel('Subject'), axis square
-
- subplot(3,1,2), bar(H)
- title('Conditional entropy','FontSize',16)
- xlabel('Subject'), axis square
-
- subplot(3,1,3), bar(T)
- title('Posterior variance','FontSize',16)
- xlabel('Subject'), axis square
- end
- %-Average models using Bayesian fixed-effects analysis -> average Ep,Cp
- %==========================================================================
- % averaged posterior covariance
- %--------------------------------------------------------------------------
- Cp = spm_inv(sum(miCp,3));
- % averaged posterior mean
- %--------------------------------------------------------------------------
- pE = spm_vec(DCM.M.pE);
- wEp = 0;
- for model = 1:N
- wEp = wEp + miCp(:,:,model)*mEp(:,model);
- end
- Ep = Cp*wEp;
- % project back through U
- %--------------------------------------------------------------------------
- Cp = U*Cp*U';
- Ep = U*Ep + pE - U*U'*pE;
- Ep = spm_unvec(Ep,DCM.M.pE);
- %-Copy contents of first DCM into the output DCM and add BPA
- %==========================================================================
- DCM = DCM_first;
- DCM.averaged = true;
- try
- DCM.models = char(P);
- end
- % compute posterior probabilities and variance
- %--------------------------------------------------------------------------
- sw = warning('off','SPM:negativeVariance');
- Vp = diag(Cp);
- Pp = 1 - spm_Ncdf(0,abs(spm_vec(Ep) - spm_vec(pE)),Vp);
- warning(sw);
- DCM.Ep = Ep;
- DCM.Cp = Cp;
- DCM.Vp = spm_unvec(Vp,DCM.M.pE);
- DCM.Pp = spm_unvec(Pp,DCM.M.pE);
- %-Save new DCM if there are no output arguments
- %==========================================================================
- if nocond
- DCM.name = [name ' (FFX average - no conditional dependencies)'];
- else
- DCM.name = [name ' (Bayesian FFX average)'];
- end
- if ~nargout
- save(['DCM_avg_' name '.mat'], 'DCM', spm_get_defaults('mat.format'));
- end
- % Warn the user how this average DCM should NOT be used
- %--------------------------------------------------------------------------
- % disp(['Results of averaging DCMs were saved in DCM_avg_' name '.mat.']);
- % disp('Please note that this file only contains average parameter estimates');
- % disp('and their posterior probabilities, but NOT averaged time series.');
- % disp('Also, note that this file can NOT be used for model comparisons.');
|