-
Notifications
You must be signed in to change notification settings - Fork 28
/
palm_competitive.m
143 lines (133 loc) · 4.6 KB
/
palm_competitive.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
function [unsrtR,S,srtR] = palm_competitive(X,ord,mod)
% Sort a set of values and return their competition
% ranks, i.e., 1224, or the modified competition ranks,
% i.e. 1334. This makes difference only when there are
% ties in the data. The function returns the ranks in
% their original order as well as sorted.
%
% Usage:
% [unsrtR,S,srtR] = palm_competitive(X,ord,mod)
%
% Inputs:
% - X : 2D array with the original data. The
% function operates on columns. To operate
% on rows or other dimensions, use transpose
% or permute the array's higher dimensions.
% - ord : Sort as 'ascend' (default) or 'descend'.
% - mod : If true, returns the modified competition
% ranks, i.e., 1334. This is the
% correct for p-values and cdf. Otherwise
% returns standard competition ranks.
%
% Outputs:
% - unsrtR : Competitive ranks in the original order.
% - S : Sorted values, just as in 'sort'.
% - srtR : Competitive ranks sorted as in S.
%
% Examples:
% - To obtain the empirical cdf of a dataset in X, use:
% cdf = palm_competitive(X,'ascend',true)/size(X,1);
% - To obtain the empirical p-values for each value in X, use:
% pvals = palm_competitive(X,'descend',true)/size(X,1);
%
% _____________________________________
% Anderson M. Winkler
% FMRIB / University of Oxford
% Nov/2012
% http://brainder.org
% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
% PALM -- Permutation Analysis of Linear Models
% Copyright (C) 2015 Anderson M. Winkler
%
% 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 3 of the License, or
% 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, see <http://www.gnu.org/licenses/>.
% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
% Check inputs
if nargin < 1 || nargin > 3
error('Incorrect number of arguments.');
elseif nargin == 1
ord = 'ascend';
mod = false;
elseif nargin == 2
mod = false;
end
% Important: The function starts by computing the
% unmodified competition ranking. This can be
% ascending or descending. However, note that the
% modified ranking for the ascending uses the
% unmodified descending, whereas the modified
% descending uses the modified ascending, hence
% the need to "reverse" the inputs below.
if mod
if strcmpi(ord,'ascend')
ord = 'descend';
elseif strcmpi(ord,'descend')
ord = 'ascend';
end
end
% Unmodified competition ranking
[nR,nC] = size(X);
unsrtR = single(zeros(size(X)));
[S,tmp] = sort(X,ord);
[~,rev] = sort(tmp);
srtR = repmat((1:nR)',[1 nC]);
for c = 1:nC % loop over columns
% Check for +Inf and -Inf and replace them
% for a value just higher or smaller than
% the max or min, respectively.
infpos = isinf(S(:,c)) & S(:,c) > 0;
infneg = isinf(S(:,c)) & S(:,c) < 0;
if all(infpos | infneg)
error(['Data cannot be sorted. Maximum statistic is +Inf or -Inf\n', ...
'for all permutations. Make sure that the input data, design\n', ...
'and contrasts are meaningful.%s'],'');
end
if any(infpos)
S(infpos,c) = max(S(~infpos,c)) + 1;
end
if any(infneg)
S(infneg,c) = min(S(~infneg,c)) - 1;
end
% Do the actual sorting, checking for obnoxious NaNs
dd = diff(S(:,c));
if any(isnan(dd))
error(['Data cannot be sorted. Check for NaNs that might be present,\n', ...
'or precision issues that may cause over/underflow.\n', ...
'If you are using "-approx tail", consider adding "-nouncorrected".%s'],'');
end
f = find([false; ~logical(dd)]);
for pos = 1:numel(f)
srtR(f(pos),c) = srtR(f(pos)-1,c);
end
unsrtR(:,c) = single(srtR(rev(:,c),c)); % original order as the data
% Put the infinities back
if any(infpos)
S(infpos,c) = +Inf;
end
if any(infneg)
S(infneg,c) = -Inf;
end
end
% Prepare the outputs for the modified rankings, i.e.,
% flip the sorted values and ranks
if mod
% Do the actual modification
unsrtR = nR - unsrtR + 1;
% Flip outputs
if nargout >= 2
S = flipud(S);
end
if nargout == 3
srtR = flipud(nR - srtR + 1);
end
end