-
Notifications
You must be signed in to change notification settings - Fork 9
/
imapLMM.m
executable file
·313 lines (302 loc) · 14.5 KB
/
imapLMM.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
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
function [LMMmap,lmexample] = imapLMM(FixMap,PredictorM,Mask,opt,formula,varargin)
% Usage: [LMMmap,lmexample] = imapLMM(FixMap,PredictorM,Mask,opt,formula,varargin)
% Input: FixMap - total number of trials * xSize * ySize
% PredictorM - dataset format of condition Matrix, total number of
% trials * number of predictor. Categorical column must
% set to nominal
% Mask - 2D mask, for reducing the number of computation
% opt - structure. option to define parallel grid (opt.parallelname)
% and option to compute each single categorical condition
% beta (opt.singlepredi)
% formula/varargin - same as fitlme, type '>>help fitlme' for more
% information
%
% Only apply when the input Predictor Matrix has non-orthogonal categorical
% predictor. Categorical beta of each condition will be compute separately
% when opt.singlepredi is set to 1.
% PredictorMatrix should include one subject colume to indicate group for
% the estimation of random effect.
% The function will run in Parallel if Parallel Computing Toolbox is
% installed in Matlab. Parallel cluster could be specify in
% opt.parallelname (default 'local')
% Same varargin apply as fitlme in matlab. For more information
% help fitlme
% See also fitlme, LinearMixedModel, LinearModel, GeneralizedLinearModel, NonLinearModel.
%
% 2014-11-08 Code updated to sort out compatible issue with Matlab 2014b
% 2015-02-12 Junpeng Lao, University of Fribourg.
%--------------------------------------------------------------------------
% Copyright (C) iMap Team 2015
%% check Matlab version and toolbox before start
v=ver;
if size(PredictorM,1) ~= size(FixMap,1)
error('Number of items/trials mismatch between PredictorM and FixMap, please double check your input matrix.')
end
if exist('LinearMixedModel') == 0
error('Some crucial toolboxes are missing in your current version of Matlab for imapLMM to run.')
end
has_fsolve = any(strcmp({v.Name},'Parallel Computing Toolbox'));
if has_fsolve == 1
if isfield(opt,'parallelname') == 0
gridname = 'local';
else
gridname = opt.parallelname;
end
disp('imapLMM will be computed in parallel mode, you machine might become quite slow during the computation.')
end
if isfield(opt,'singlepredi') == 1;
singlep = opt.singlepredi;
if singlep ~= 0
disp('Single predictor beta for each categorical condition will be computed.')
end
end
% create save structure
LMMmap = struct;
LMMmap.runopt = opt;
% check mask
ySize2 = size(FixMap,2);
xSize2 = size(FixMap,3);
if isempty(Mask) == 1
Mask = ones(ySize2,xSize2);
end
compuIdx = find(Mask(:) == 1);
if isempty(compuIdx)
error('Empty Mask! Please double check your input.')
end
numCompute = length(compuIdx);
% run one model as example to create matrix for saving
tic;
% indextmp = compuIdx(randi(numCompute));
valall = squeeze(nanmean(FixMap,1));
indextmp = valall(compuIdx) == max(valall(compuIdx));
tbl = PredictorM;% construct lme table
tbl.PixelIntensity = FixMap(:,indextmp);
if isa(tbl,'dataset')
VarNames = tbl.Properties.VarNames;
elseif isa(tbl,'table')
VarNames = tbl.Properties.VariableNames;
% In Matlab 2013b the LinearMixedModel class only accept dataset
% input. Transform input into dataset for backwards-compatible.
% However, dataset format might be remove in the future release. A
% conditioning for Matlab version should be implemented by then.
tbl = table2dataset(tbl);
PredictorM = table2dataset(PredictorM);
else
error('Please reform your input predictor matrix as dataset!')
end
lmexample = LinearMixedModel.fit(tbl,formula,varargin{:});
[~,~,randstat] = randomEffects(lmexample);
time=toc;
disp(lmexample)
estimatime = time*numCompute*(2-(singlep == 0))/60;
disp(['The total computation time is around ' num2str(estimatime) ...
' minutes without parallel computation.'])
% save information
LMMmap.VariableInfo = lmexample.VariableInfo;
LMMmap.Variables = tbl;
LMMmap.FitMethod = lmexample.FitMethod;
LMMmap.Formula = lmexample.Formula;
LMMmap.modelX = designMatrix(lmexample);
LMMmap.FitOptions = varargin;
LMMmap.modelDFE = lmexample.DFE;
LMMmap.CoefficientNames = lmexample.CoefficientNames;
% save Anova information
statexample = anova(lmexample);% no need to save pValue=1-fcdf(FStat,DF1,DF2);
LMMmap.Anova.Term = statexample.Term;
LMMmap.Anova.DF1 = statexample.DF1;
LMMmap.Anova.DF2 = statexample.DF2;
AnovaFStat = NaN(size(statexample.Term,1), ySize2, xSize2);
Covb = NaN([size(lmexample.CoefficientCovariance), ySize2, xSize2]);
MSEmatrix = NaN(ySize2,xSize2);
SSEmatrix = MSEmatrix;
SSTmatrix = MSEmatrix;
SSRmatrix = MSEmatrix;
RsquaredMatrix = NaN(2,ySize2,xSize2);
ModelCriterionMatrix = NaN(4,ySize2,xSize2);% AIC,BIC,LogLikelihood,Deviance
CoefficientsMatrix = NaN(length(lmexample.CoefficientNames), 2, ySize2, xSize2);% save beta, SE
% for parallel computing
pAnovaFStat = NaN(size(statexample.Term,1),numCompute);
pCovb = NaN([size(lmexample.CoefficientCovariance),numCompute]);
pMSEmatrix = NaN(1,numCompute);
pSSEmatrix = pMSEmatrix;
pSSTmatrix = pMSEmatrix;
pSSRmatrix = pMSEmatrix;
pRsquaredMatrix = NaN(2,numCompute);
pModelCriterionMatrix = NaN(4,numCompute);% AIC,BIC,LogLikelihood,Deviance
pCoefficientsMatrix = NaN(length(lmexample.CoefficientNames),2,numCompute);% save beta, SE
if singlep ~= 0
coefname = lmexample.CoefficientNames;
categypredi = lmexample.VariableInfo.InModel ...
& lmexample.VariableInfo.IsCategorical;
categyprediname = VarNames(categypredi);
% remove subject/grouping/random predictor if there is any
exclu1 = zeros(length(categyprediname),1);
for icate = 1:length(categyprediname)
if isempty(strmatch(categyprediname{icate},coefname))
exclu1(icate) = 1;
end
end
categyprediname( exclu1==1 ) = [];
Ncatepred = length(categyprediname);
if Ncatepred == 0
singlep = 0;
else
label = cell(length(tbl),Ncatepred);
strlabel = cell(length(tbl),1);
for icc = 1:Ncatepred
label(:,icc) = cellstr(eval(['tbl.' categyprediname{icc}]));
end
for ii = 1:size(label,1)
strlabel{ii,:} = strjoin(label(ii,:),'_');
end
CatePredictor = unique(strlabel);
CatePredictor = strcat({'c'},CatePredictor);
rangroupname = lmexample.Formula.GroupingVariableNames;
ranprediname = cell(size(rangroupname));
groupingvar = cell(size(rangroupname));
DZ = cell(size(rangroupname));
groupname = [];
for ir = 1:length(ranprediname)
ranprediname{ir} = {'Intercept'};
groupingvar{ir} = eval(['tbl.' char(rangroupname{ir})]);
DZ{ir} = ones(size(groupingvar{ir}));
groupname=[groupname,rangroupname{ir}];
end
DS = dummyvar(nominal(strlabel));
CoefficientsMatrix2 = NaN(length(CatePredictor), 2, ySize2, xSize2);% save beta, SE
Covb2 = NaN(length(CatePredictor), length(CatePredictor), ySize2, xSize2);
pCoefficientsMatrix2 = NaN(length(CatePredictor), 2, numCompute);% save beta, SE
pCovb2 = NaN(length(CatePredictor), length(CatePredictor), numCompute);
LMMmap.SinglePred.CatePredictor = CatePredictor;
LMMmap.SinglePred.DesignMatrix = DS;
end
end
pRandomStat = NaN(size(randstat,1),2,numCompute);% Estimate,SEPred
LMMmap.RandomEffects.Group = randstat.Group;
LMMmap.RandomEffects.Level = randstat.Level;
LMMmap.RandomEffects.Name = randstat.Name;
LMMmap.RandomEffects.DF = randstat.DF;
LMMmap.RandomEffects.DX = designMatrix(lmexample,'Random');
RandomStat = NaN(size(randstat,1), 2, ySize2, xSize2);
FixMap2 = FixMap(:,compuIdx);
if has_fsolve == 1
% parpool;
try parpool(gridname);end
switch singlep
case 0
parfor ip = 1:numCompute
fprintf('.')
% construct lme table
tbl = PredictorM;
tbl.PixelIntensity = FixMap2(:,ip);
% fit model
lme = LinearMixedModel.fit(tbl,formula,varargin{:});
% Ftest
stats = anova(lme);
% save result
pAnovaFStat (:,ip) = double(stats(:,2));
pCovb (:,:,ip) = lme.CoefficientCovariance;
pMSEmatrix (ip) = lme.MSE;
pSSEmatrix (ip) = lme.SSE;
pSSTmatrix (ip) = lme.SST;
pSSRmatrix (ip) = lme.SSR;
pRsquaredMatrix (:,ip) = [lme.Rsquared.Ordinary lme.Rsquared.Adjusted];
pModelCriterionMatrix(:,ip) = double(lme.ModelCriterion);% AIC,BIC,LogLikelihood,Deviance
pCoefficientsMatrix(:,:,ip) = double(lme.Coefficients(:,[2 3]));% save beta, SE
[~,~,stat] = randomEffects(lme);
pRandomStat (:,:,ip) = double(stat(:,[4 5]));% Estimate,SEPred
end
otherwise
parfor ip = 1:numCompute
fprintf('.')
% construct lme table
tbl = PredictorM;
tbl.PixelIntensity = FixMap2(:,ip);
% fit model
lme = LinearMixedModel.fit(tbl,formula,varargin{:});
% Ftest
stats = anova(lme);
% save result
pAnovaFStat (:,ip) = double(stats(:,2));
pCovb (:,:,ip) = lme.CoefficientCovariance;
pMSEmatrix (ip) = lme.MSE;
pSSEmatrix (ip) = lme.SSE;
pSSTmatrix (ip) = lme.SST;
pSSRmatrix (ip) = lme.SSR;
pRsquaredMatrix (:,ip) = [lme.Rsquared.Ordinary lme.Rsquared.Adjusted];
pModelCriterionMatrix (:,ip) = double(lme.ModelCriterion);% AIC,BIC,LogLikelihood,Deviance
pCoefficientsMatrix (:,:,ip) = double(lme.Coefficients(:,[2 3]));% save beta, SE
lme2 = LinearMixedModel.fitmatrix(DS,tbl.PixelIntensity,DZ,groupingvar, ...
'FixedEffectPredictors',CatePredictor, ...
'ResponseVarName','PixelIntensity', ...
'RandomEffectGroups',groupname, ...
'RandomEffectPredictors',ranprediname);
pCovb2 (:,:,ip) = lme2.CoefficientCovariance;
pCoefficientsMatrix2(:,:,ip) = double(lme2.Coefficients(:,[2 3]));% save beta, SE
[~,~,stat] = randomEffects(lme);
pRandomStat (:,:,ip) = double(stat(:,[4 5]));% Estimate,SEPred
end
end
% delete(gcp)
else
h = waitbar(0,'Fitting LMM, please wait...');
for ip = 1:numCompute
waitbar(ip / numCompute)
% construct lme table
tbl = PredictorM;
tbl.PixelIntensity = FixMap2(:,ip);
% fit model
lme = LinearMixedModel.fit(tbl,formula,varargin{:});
% Ftest
stats = anova(lme);
% save result
pAnovaFStat (:,ip) = double(stats(:,2));
pCovb (:,:,ip) = lme.CoefficientCovariance;
pMSEmatrix (ip) = lme.MSE;
pSSEmatrix (ip) = lme.SSE;
pSSTmatrix (ip) = lme.SST;
pSSRmatrix (ip) = lme.SSR;
pRsquaredMatrix (:,ip) = [lme.Rsquared.Ordinary lme.Rsquared.Adjusted];
pModelCriterionMatrix (:,ip) = double(lme.ModelCriterion);% AIC,BIC,LogLikelihood,Deviance
pCoefficientsMatrix (:,:,ip) = double(lme.Coefficients(:,[2 3]));% save beta, SE
if singlep~=0
lme2 = LinearMixedModel.fitmatrix(DS,tbl.PixelIntensity,DZ,groupingvar, ...
'FixedEffectPredictors',CatePredictor, ...
'ResponseVarName','PixelIntensity', ...
'RandomEffectGroups',groupname, ...
'RandomEffectPredictors',ranprediname);
pCovb2 (:,:,ip) = lme2.CoefficientCovariance;
pCoefficientsMatrix2(:,:,ip) = double(lme2.Coefficients(:,[2 3]));% save beta, SE
end
[~,~,stat] = randomEffects(lme);
pRandomStat (:,:,ip) = double(stat(:,[4 5]));% Estimate,SEPred
end
close(h)
end
AnovaFStat (:,compuIdx) = pAnovaFStat;
Covb (:,:,compuIdx) = pCovb;
MSEmatrix (compuIdx) = pMSEmatrix;
SSEmatrix (compuIdx) = pSSEmatrix;
SSTmatrix (compuIdx) = pSSTmatrix;
SSRmatrix (compuIdx) = pSSRmatrix;
RsquaredMatrix (:,compuIdx) = pRsquaredMatrix;
ModelCriterionMatrix (:,compuIdx) = pModelCriterionMatrix;
CoefficientsMatrix (:,:,compuIdx) = pCoefficientsMatrix;
LMMmap.Anova.FStat = AnovaFStat;
LMMmap.CoefficientCovariance = Covb;
LMMmap.MSE = MSEmatrix;
LMMmap.SSE = SSEmatrix;
LMMmap.SST = SSTmatrix;
LMMmap.SSR = SSRmatrix;
LMMmap.Rsquared = RsquaredMatrix;
LMMmap.ModelCriterion = ModelCriterionMatrix;% AIC,BIC,LogLikelihood,Deviance
LMMmap.Coefficients = CoefficientsMatrix;% save beta, SE
if singlep ~= 0
Covb2 (:,:,compuIdx) = pCovb2;
CoefficientsMatrix2(:,:,compuIdx) = pCoefficientsMatrix2;
LMMmap.SinglePred.beta = CoefficientsMatrix2;
LMMmap.SinglePred.Covb = Covb2;
end
RandomStat (:,:,compuIdx) = pRandomStat;
LMMmap.RandomEffects.RandomStat = RandomStat;
end