spm_dcm_bdc.m 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. function [d,BMA,PEBs] = spm_dcm_bdc(GCMs,field,M,ynames)
  2. % Compare datasets using DCM and PEB (Bayesian data comparison)
  3. %
  4. % Performs the following procedure:
  5. %
  6. % 1. Identifies the optimum reduced model (PEB) collapsed over datasets.
  7. % 2. For each dataset, creates reduced GCMs based on the optimum model
  8. % above and estimates a per-dataset PEB model.
  9. % 3. Computes a series of measures on each dataset's PEB model
  10. %
  11. % Inputs:
  12. %
  13. % GCMs - {1 x ny} cell array of filenames, each of which is a GCM file.
  14. % field - {1 x nf} cell array of field names, e.g. {'A','B'}
  15. % M - (Optional) struct for configuring PEB. See spm_dcm_peb.m .
  16. % ynames - (Optional) {1 x ny} cell array of names for each dataset
  17. %
  18. % ny = number of datasets, nf = number of DCM fields
  19. %
  20. % Returns:
  21. %
  22. % d.precisions - [np x ny] Precision of each DCM parameter in each dataset
  23. % d.dcm_negent - [1 x ny] Negative entropy (certainty) of DCM parameters
  24. % d.rfx_negent - [1 x ny] Negative entropy (certainty) of the estimated
  25. % between-subject variability
  26. % d.complexity - [1 x ny] Number of effective parameters in the model
  27. % d.model_KL - [1 x ny] Ability to disriminate between similar models
  28. %
  29. % BMA - Bayesian model average across all datasets
  30. % PEBs - [1 x ny] PEB for each dataset
  31. %__________________________________________________________________________
  32. % Copyright (C) 2018 Wellcome Trust Centre for Neuroimaging
  33. % Peter Zeidman & Samira Kazan
  34. % $Id: spm_dcm_bdc.m 7315 2018-05-20 10:42:51Z peter $
  35. % Load and concatenate models across datasets
  36. % -------------------------------------------------------------------------
  37. GCM = {};
  38. for i = 1:length(GCMs)
  39. if ischar(GCMs{i})
  40. gcm = load(GCMs{i});
  41. gcm = gcm.GCM;
  42. else
  43. gcm = GCMs{i};
  44. end
  45. GCM = [GCM; gcm(:,1)];
  46. end
  47. ns = size(gcm,1); % Number of subjects
  48. ny = length(GCMs); % Number of datasets
  49. nm = ns*ny; % Number of DCMs
  50. % Set defaults
  51. % -------------------------------------------------------------------------
  52. if nargin < 2 || isempty(field), field = {'B'}; end
  53. if nargin < 3, M = []; end
  54. if nargin < 4 || isempty(ynames)
  55. ynames = cell(1,ny);
  56. for i = 1:ny
  57. ynames{i} = sprintf('Dataset %d',i);
  58. end
  59. end
  60. % Identify optimum model structure across all datasets
  61. % -------------------------------------------------------------------------
  62. % Perform PEB analysis
  63. if isempty(M)
  64. M = struct();
  65. M.alpha = 1;
  66. M.beta = 16;
  67. M.hE = 0;
  68. M.hC = 1/16;
  69. M.Q = 'single';
  70. M.X = ones(nm,1);
  71. end
  72. PEB = spm_dcm_peb(GCM,M,field);
  73. % Prune full model
  74. BMA = spm_dcm_peb_bmc(PEB);
  75. % Estimate PEBs for each dataset using the optimal DCM structure from above
  76. % -------------------------------------------------------------------------
  77. % Identify enabled PEB parameters
  78. is_disabled = find(BMA.Pp < 1/1000);
  79. % Get indices of disabled parameters
  80. disabled_pidx = BMA.Pind(is_disabled);
  81. % Update design matrix
  82. M.X = ones(ns,1);
  83. PEBs = {};
  84. for i = 1:ny
  85. % Load dataset
  86. GCM = load(GCMs{i});
  87. GCM = GCM.GCM;
  88. % Build prior covariance
  89. rE = GCM{1}.M.pE;
  90. rC = GCM{1}.M.pC;
  91. for j = 1:length(disabled_pidx)
  92. rC(disabled_pidx(j),disabled_pidx(j)) = 0;
  93. end
  94. % Apply priors at DCM level
  95. GCM = spm_dcm_reduce(GCM, rE, rC);
  96. % Build PEB
  97. PEBs{i} = spm_dcm_peb(GCM,M,field);
  98. end
  99. % Compute measures
  100. % -------------------------------------------------------------------------
  101. d = struct();
  102. d.precisions = [];
  103. d.dcm_negent = [];
  104. d.rfx_negent = [];
  105. d.complexity = [];
  106. for i = 1:ny
  107. % Certainty about RFX
  108. d.rfx_negent(i) = -0.5 * spm_logdet(2 * pi * exp(1) * PEBs{i}.Ch);
  109. % Certainty about parameters
  110. d.dcm_negent(i) = -0.5 * spm_logdet(2 * pi * exp(1) * PEBs{i}.Cp);
  111. % Information gain (KL-divergence) over parameters
  112. qE = PEBs{i}.Ep; % Posterior expectations
  113. pE = PEBs{i}.M.pE; % Prior expectations
  114. qC = PEBs{i}.Cp; % Posterior covariance
  115. pC = PEBs{i}.M.pC; % Prior covariance
  116. k = rank(full(pC));
  117. ipC = pinv(pC);
  118. d.complexity(i) = 0.5 * trace(ipC*qC) + (pE - qE)'*ipC*(pE - qE) - k + log(det(pC) / det(qC));
  119. end
  120. % Assess model discrimination
  121. % -------------------------------------------------------------------------
  122. % Calculate evidence for reduced models with each connection switched off
  123. Fs = []; % models x datasets
  124. for i = 1:ny
  125. qE = PEBs{i}.Ep;
  126. qC = PEBs{i}.Cp;
  127. pE = PEBs{i}.M.pE;
  128. pC = PEBs{i}.M.pC;
  129. for m = 1:length(pE)
  130. rE = pE;
  131. rC = pC;
  132. rC(m,m) = 0;
  133. Fs(m,i) = spm_log_evidence_reduce(qE,qC,pE,pC,rE,rC);
  134. end
  135. end
  136. % Retain nr difficult to discriminate models
  137. i = find(mean(Fs,2) > -3);
  138. nr = numel(i);
  139. % Evidence -> probability
  140. p = spm_softmax(Fs(i,:));
  141. % KL divergence (information gain)
  142. d.model_KL = sum(p.*log(p)) + log(nr);
  143. % Get PEB parameter precisions for each dataset
  144. % -------------------------------------------------------------------------
  145. for i = 1:ny
  146. d.precisions(:,i) = diag(spm_inv(PEBs{i}.Cp));
  147. end
  148. % Plot PEB parameters for each dataset
  149. % -------------------------------------------------------------------------
  150. spm_figure('GetWin','Datasets');
  151. rows = max(ceil(ny / 2),3);
  152. cols = 2;
  153. for i = 1:ny
  154. subplot(rows,cols,i);
  155. spm_plot_ci(PEBs{i}.Ep,PEBs{i}.Cp);
  156. title(ynames{i},'FontSize',16);
  157. xlabel('PEB Parameter','FontSize',12);
  158. ylabel('Estimate','FontSize',12);
  159. ylim([-2 2]);
  160. end
  161. % Plot measures
  162. % -------------------------------------------------------------------------
  163. spm_figure('GetWin','Data Comparison');
  164. spm_clf;
  165. rows = 3; cols = 2;
  166. subplot(rows,cols,1:2);
  167. bar(d.precisions);
  168. title('Parameter certainty','FontSize',16);
  169. xlabel('Parameter','FontSize',12); ylabel('Precision','FontSize',12);
  170. legend(ynames,'Location','South','Orientation','horizontal','FontSize',12);
  171. subplot(rows,cols,3);
  172. bar(d.dcm_negent - min(d.dcm_negent));
  173. title('Parameter certainty','FontSize',16);
  174. xlabel('Dataset','FontSize',12); ylabel('Relative neg entropy (nats)','FontSize',12);
  175. subplot(rows,cols,4);
  176. bar(d.rfx_negent - min(d.rfx_negent));
  177. title('RFX certainty','FontSize',16);
  178. xlabel('Dataset','FontSize',12); ylabel('Relative neg entropy (nats)','FontSize',12);
  179. subplot(rows,cols,5);
  180. bar(d.complexity-min(d.complexity));
  181. title('Information gain (parameters)','FontSize',14);
  182. xlabel('Dataset','FontSize',12); ylabel('Relative neg entropy (nats)','FontSize',12);
  183. subplot(rows,cols,6);
  184. bar(d.model_KL-min(d.model_KL));
  185. title(sprintf('Information gain (%d models)',nr),'FontSize',14);
  186. xlabel('Dataset','FontSize',12);
  187. xlabel('Dataset','FontSize',12); ylabel('Relative entropy (nats)','FontSize',12);