-
Notifications
You must be signed in to change notification settings - Fork 4
/
clusterLevelPermutationTest.m
150 lines (128 loc) · 6.1 KB
/
clusterLevelPermutationTest.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
% clusterLevelPermutationTest() - Performs permutation test between two samples. For multiple comparison
% correction, cluster-level correction is applied [1].
%
% Reference: [1] Groppe, Urbach, Kutas, 2011. Mass univariate analysis of
% event-related brain potentials/fields I: A critical tutorial
% review. Psychophysiology, xx, 1-15. (See also Korn et al.,
% 2004)
%
% Usage
% >> [mask, tScore, pValue] = clusterLevelPermutationTest(input1, input2, repeatedMeasuresFlag, pValForPreselection, numIterations)
%
% Input
% input1, input2: Data matrices. For example, the first dimension is ERP or
% vectorized time-frequency measure, and the second dimension is
% ICs or subjects.
% repeatedMeasuresFlag: 1, paired t-test; 0, two-sample t-test.
% pValForPreselection: This determines the cluster size.
% numIteration: Number of bootstrap iteration (recommended: 10000)
%
% Output
% mask : logical mask for significant
%
% tScore: The tScore is for input1-input2. Positive result means input1 > input2
% (same as ttest2). This is computed by Zhou-Gao-Hui
% bootstrap method to compute tScore.
% pValue: This is computed by standard bootstrap test.
% History
% 06/28/2020 Makoto.
% 05/23/2020 Makoto. Cleaned code.
% 03/02/2017 Makoto. Created.
%
% Copyright (C) 2017 Makoto Miyakoshi, SCCN,INC,UCSD;
%
% This program is free software; you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation; either version 2 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program; if not, write to the Free Software
% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
function [mask, tScore, pValue, surroMassOfCluster] = clusterLevelPermutationTest(input1, input2, repeatedMeasuresFlag, pValForPreselection, numIterations)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Perform t-test for true difference %%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
input1_2D = reshape(input1, [size(input1,1)*size(input1,2) size(input1,3)]);
input2_2D = reshape(input2, [size(input2,1)*size(input2,2) size(input2,3)]);
if repeatedMeasuresFlag == 1
[~, pValues, ~, stats] = ttest( input1_2D', input2_2D');
else
[~, pValues, ~, stats] = ttest2(input1_2D', input2_2D');
end
% Compute cluster statistics.
pVal_2D = reshape(pValues, [size(input1,1) size(input1,2)]);
tScore_2D = reshape(stats.tstat, [size(input2,1) size(input2,2)]);
pvalMask = pVal_2D< pValForPreselection;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% If no significant result in the uncorrected result, exit (to save time). %%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
if any(pvalMask(:))==0
disp('No significant result.')
mask = zeros(size(input1,1), size(input1,2));
tScore = zeros(size(input1,1), size(input1,2));
pValue = ones( size(input1,1), size(input1,2));
surroMassOfCluster = zeros(numIterations, 2);
return
end
% Extract clusters of significant pixels.
connectedComponentLabels = bwlabeln(pvalMask); % This requires image processing toolbox
[entryCount, blobId] = hist(connectedComponentLabels(:), unique(connectedComponentLabels(:)));
massOfCluster = zeros(length(blobId),1);
for n = 1:length(blobId)
currentMask = connectedComponentLabels==blobId(n);
massOfCluster(n) = sum(sum(currentMask.*tScore_2D));
end
massOfCluster = massOfCluster(2:end);
% Prepare outputs.
tScore = tScore_2D;
pValue = pVal_2D;
mask = connectedComponentLabels;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Perform surrogate test %%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
surroMassOfCluster = zeros(numIterations,2);
combinedData = [input1_2D input2_2D];
permSize = size(combinedData,2);
for iterationIdx = 1:numIterations
% % Report progress.
% if mod(iterationIdx, 500) == 0
% disp(sprintf('%.0f/%.0f...', iterationIdx, numIteration))
% end
% Perform t-test
permIdx = randperm(permSize);
surro1 = combinedData(:,permIdx(1:size(input1_2D,2)));
surro2 = combinedData(:,permIdx(size(input1_2D,2)+1:end));
if repeatedMeasuresFlag == 1
[~, pValuesSurro, ~, statsSurro] = ttest(surro1', surro2');
else
[~, pValuesSurro, ~, statsSurro] = ttest2(surro1', surro2');
end
% Compute cluster statistics
pValSurro_2D = reshape(pValuesSurro, [size(input1,1) size(input1,2)]);
tScoreSurro_2D = reshape(statsSurro.tstat, [size(input2,1) size(input2,2)]);
pvalSurroMask = pValSurro_2D< pValForPreselection;
% If no significant result in the uncorrected result, exit (to save time).
if any(pvalSurroMask(:))==0
% disp('No significant result.')
continue
end
% Extract clusters of significant pixels
connectedComponentLabels = bwlabeln(pvalSurroMask); % This requires image processing toolbox
[entryCount, blobId] = hist(connectedComponentLabels(:), unique(connectedComponentLabels(:)));
massOfClusterSurro = zeros(length(blobId),1);
for n = 1:length(blobId)
currentMask = connectedComponentLabels==blobId(n);
massOfClusterSurro(n) = sum(sum(currentMask.*tScore_2D));
end
if sum(pvalSurroMask(:)) ~= size(pvalSurroMask,1)*size(pvalSurroMask,2) % if equal, it means all the points/pixels are significant so no 'background'.
massOfClusterSurro = massOfClusterSurro(2:end);
end
% Store the minimum and maximum of massOfClusterSurro
surroMassOfCluster(iterationIdx,:) = [min(massOfClusterSurro) max(massOfClusterSurro)];
end