|
1 |
| -% THIS SCRIPT RUNS BETWEEN-PERSON CONTRASTS using second-level regression |
| 1 | +% THIS SCRIPT RUNS BETWEEN-PERSON (2nd-level) Regression analyses |
| 2 | +% for each within-person CONTRAST registered in the analysis |
| 3 | +% |
| 4 | +% - To specify analysis options, run a2_set_default_options |
| 5 | +% - prep_3a_run_second_level_regression_and_save runs regressions and saves |
| 6 | +% results in a standard location and format |
| 7 | +% - To get results reports, see c2a_second_level_regression |
2 | 8 | %
|
3 |
| -% FOR NOW: Uses "group" variable. |
4 |
| -% FUTURE: Extend this to arbitrary covariates (> 1 cov), which have to be |
5 |
| -% entered in DAT structure in some standardize place. |
| 9 | +% Analysis options include: |
| 10 | +% - dorobust : robust regression or OLS (true/false) |
| 11 | +% - myscaling: 'raw' or 'scaled' (image scaling done in prep_2_... data load) |
| 12 | +% - design_matrix_type: 'group' or 'custom' |
| 13 | +% Group: use DAT.BETWEENPERSON.group or DAT.BETWEENPERSON.contrasts{c}.group; |
| 14 | +% Custom: use all columns of table object DAT.BETWEENPERSON.contrasts{c}; |
6 | 15 | %
|
7 |
| -% Assuming that groups are concatenated into contrast image lists. |
8 |
| -% Requires DAT.BETWEENPERSON.group field specifying group membership for |
| 16 | +% 'group' option |
| 17 | +% Assuming that groups are concatenated in contrast image lists, and |
| 18 | +% regressor values of 1 or -1 will specify the group identity for each |
| 19 | +% image. Requires DAT.BETWEENPERSON.group field specifying group membership for |
9 | 20 | % each image.
|
| 21 | +% |
| 22 | +% 'custom' option: |
| 23 | +% Can enter a multi-column design matrix for each contrast |
| 24 | +% Design matrix can be different for each contrast |
| 25 | +% |
| 26 | +% To set up group and custom variables, see prep_1b_prep_behavioral_data |
10 | 27 |
|
11 | 28 | % --------------------------------------------------------------------
|
12 | 29 |
|
|
21 | 38 | % (e.g., not specified in an older/incomplete copy of a2_set_default_options)
|
22 | 39 |
|
23 | 40 | % Now set in a2_set_default_options
|
24 |
| -options_needed = {'dorobust', 'myscaling'}; % Options we are looking for. Set in a2_set_default_options |
| 41 | +options_needed = {'dorobust', 'myscaling', 'design_matrix_type'}; % Options we are looking for. Set in a2_set_default_options |
25 | 42 | options_exist = cellfun(@exist, options_needed);
|
26 | 43 |
|
27 |
| -option_default_values = {false 'raw'}; % defaults if we cannot find info in a2_set_default_options at all |
| 44 | +option_default_values = {false, 'raw', 'group'}; % defaults if we cannot find info in a2_set_default_options at all |
28 | 45 |
|
29 | 46 | plugin_get_options_for_analysis_script
|
30 | 47 |
|
|
65 | 82 |
|
66 | 83 | for c = 1:kc
|
67 | 84 |
|
| 85 | + % Get design matrix for this contrast |
| 86 | + % -------------------------------------------------------------------- |
| 87 | + |
68 | 88 | mygroupnamefield = 'contrasts'; % 'conditions' or 'contrasts'
|
69 |
| - [group, groupnames, groupcolors] = plugin_get_group_names_colors(DAT, mygroupnamefield, c); |
70 |
| - outcome_value = group; |
71 | 89 |
|
72 |
| - if isempty(group) |
73 |
| - fprintf('Group not defined for contrast %s. Skipping.\n', DAT.contrastnames{c}); |
74 |
| - continue |
| 90 | + switch design_matrix_type |
| 91 | + case 'custom' |
| 92 | + |
| 93 | + % Define design matrix X "design_matrix" |
| 94 | + % Use custom matrix for each condition/contrast |
| 95 | + table_obj = DAT.BETWEENPERSON.(mygroupnamefield){c}; |
| 96 | + groupnames = table_obj.Properties.VariableNames; |
| 97 | + X = table2array(table_obj); |
| 98 | + |
| 99 | + case 'group' |
| 100 | + |
| 101 | + % Use 'groups' single regressor |
| 102 | + [group, groupnames, groupcolors] = plugin_get_group_names_colors(DAT, mygroupnamefield, c); |
| 103 | + X = group; |
| 104 | + |
| 105 | + if isempty(group) |
| 106 | + fprintf('Group not defined for contrast %s. Skipping.\n', DAT.contrastnames{c}); |
| 107 | + continue |
| 108 | + end |
| 109 | + |
| 110 | + otherwise error('Incorrect option specified for design_matrix_type'); |
75 | 111 | end
|
76 |
| - |
| 112 | + |
77 | 113 | printstr(DAT.contrastnames{c});
|
78 | 114 | printstr(dashes)
|
79 | 115 |
|
|
100 | 136 |
|
101 | 137 | % a. Format and attach outcomes: 1, -1 group variable FOR NOW
|
102 | 138 | % --------------------------------------------------------------------
|
103 |
| - |
104 |
| - % Confirm outcome_value is 1, -1, or mean-centered |
105 |
| - % *****add this***** |
106 | 139 |
|
107 |
| - % Check multilinearity, variance in all regressors; error for bad |
108 |
| - % design matrix |
109 |
| - % *****add this***** |
| 140 | + % Confirm design_matrix is 1, -1, or mean-centered |
| 141 | + meancentered = ~(abs(mean(X)) > 1000 * eps); |
| 142 | + effectscoded = all(X == 1 | X == -1 | X == 0, 1); |
| 143 | + isconstant = all(X == mean(X, 1), 1); |
| 144 | + vifs = getvif(X); |
110 | 145 |
|
111 |
| - cat_obj.X = outcome_value; |
| 146 | + if any(isconstant) |
| 147 | + disp('An intercept appears to be added manually. Do not include an intercept - it will be added automatically.'); |
| 148 | + disp('Skipping this contrast.') |
| 149 | + continue |
| 150 | + end |
| 151 | + |
| 152 | + % Report |
| 153 | + design_table = table; |
| 154 | + design_table.Mean = mean(X)'; |
| 155 | + design_table.Var = var(X)'; |
| 156 | + design_table.EffectsCode = effectscoded'; |
| 157 | + design_table.VIF = vifs'; |
| 158 | + design_table.Properties.RowNames = groupnames'; |
| 159 | + disp(design_table) |
| 160 | + disp(' '); |
112 | 161 |
|
113 |
| - % Skip if necessary |
114 |
| - % -------------------------------------------------------------------- |
| 162 | + if any(~meancentered & ~effectscoded) |
| 163 | + disp('Warning: some columns are not mean-centered or effects coded. \nIntercept may not be interpretable.\n'); |
| 164 | + fprintf('Columns: ') |
| 165 | + fprintf('%d ', find(~meancentered & ~effectscoded)); |
| 166 | + fprintf('\n'); |
| 167 | + else |
| 168 | + disp('Checked OK: All columns mean-centered or are effects-coded [1 -1 0]'); |
| 169 | + end |
115 | 170 |
|
116 |
| - if all(cat_obj.X > 0) || all(cat_obj.X < 0) |
117 |
| - % Only positive or negative weights - nothing to compare |
118 |
| - |
119 |
| - printhdr(' Only positive or negative regressor values - bad design'); |
120 |
| - |
121 |
| - continue |
| 171 | + |
| 172 | + if any(vifs) > 2 |
| 173 | + disp('Some regressors have high variance inflation factors: Parameters might be poorly estimated or uninterpretable.'); |
| 174 | + else |
| 175 | + disp('Checked OK: VIFs for all columns are < 2'); |
122 | 176 | end
|
| 177 | + |
| 178 | + |
| 179 | + cat_obj.X = X; |
| 180 | + |
| 181 | + % Skip if necessary |
| 182 | + % -------------------------------------------------------------------- |
| 183 | +% |
| 184 | +% if all(cat_obj.X > 0) || all(cat_obj.X < 0) |
| 185 | +% % Only positive or negative weights - nothing to compare |
| 186 | +% |
| 187 | +% printhdr(' Only positive or negative regressor values - bad design'); |
| 188 | +% |
| 189 | +% continue |
| 190 | +% end |
123 | 191 |
|
124 | 192 | % Run voxel-wise regression model
|
125 | 193 | % --------------------------------------------------------------------
|
|
134 | 202 | % out.t has t maps for all regressors, intercept is last
|
135 | 203 | regression_stats = regress(cat_obj, .05, 'unc', robuststring, 'analysis_name', DAT.contrastnames{c}, 'variable_names', {'Group'});
|
136 | 204 |
|
| 205 | + |
137 | 206 | % Make sure variable types are right data formats
|
| 207 | + regression_stats.design_table = design_table; |
138 | 208 | regression_stats.t = enforce_variable_types(regression_stats.t);
|
139 | 209 | regression_stats.b = enforce_variable_types(regression_stats.b);
|
140 | 210 | regression_stats.df = enforce_variable_types(regression_stats.df);
|
|
146 | 216 |
|
147 | 217 | % add names for analyses and variables:
|
148 | 218 | regression_stats.analysis_name = DAT.contrastnames{c};
|
149 |
| - regression_stats.variable_names = {'Group' 'Intercept'} |
| 219 | + regression_stats.variable_names = [groupnames {'Intercept'}]; |
| 220 | + |
| 221 | + % prints output automatically - name axis |
| 222 | + for kk = 1:length(regression_stats.variable_names) |
| 223 | + spm_orthviews_name_axis(regression_stats.variable_names{kk}, kk); |
| 224 | + end |
150 | 225 |
|
151 | 226 | % Save stats objects for results later
|
152 | 227 | % --------------------------------------------------------------------
|
|
164 | 239 |
|
165 | 240 | save(savefilenamedata, 'regression_stats_results', '-v7.3');
|
166 | 241 | printhdr('Saved regression_stats_results for contrasts');
|
| 242 | +fprintf('Filename: %s\n', savefilenamedata); |
167 | 243 |
|
168 | 244 |
|
169 | 245 |
|
|
0 commit comments