6
6
# The implementations here follow this wikipedia page.
7
7
#
8
8
9
-
10
9
function _check_randparams (rks, x, p)
11
10
n = length (rks)
12
11
length (x) == length (p) == n || raise_dimerror ()
13
12
return n
14
13
end
15
14
15
+ # ranking helper function: calls sortperm(x) and then ranking method f!
16
+ function _rank (f!, x:: AbstractArray , R:: Type = Int; sortkwargs... )
17
+ rks = similar (x, R)
18
+ ord = reshape (sortperm (vec (x); sortkwargs... ), size (x))
19
+ return f! (rks, x, ord)
20
+ end
16
21
22
+ # ranking helper function for arrays with missing values
23
+ function _rank (f!, x:: AbstractArray{>: Missing} , R:: Type = Int; sortkwargs... )
24
+ inds = findall (! ismissing, vec (x))
25
+ isempty (inds) && return missings (R, size (x))
26
+ xv = disallowmissing (view (vec (x), inds))
27
+ ordv = sortperm (xv; sortkwargs... )
28
+ rks = missings (R, size (x))
29
+ f! (view (rks, inds), xv, ordv)
30
+ return rks
31
+ end
17
32
18
33
# Ordinal ranking ("1234 ranking") -- use the literal order resulted from sort
19
- function ordinalrank! (rks:: AbstractArray , x:: AbstractArray , p:: IntegerArray )
20
- n = _check_randparams (rks, x, p)
21
-
22
- if n > 0
23
- i = 1
24
- while i <= n
25
- rks[p[i]] = i
26
- i += 1
27
- end
34
+ function _ordinalrank! (rks:: AbstractArray , x:: AbstractArray , p:: IntegerArray )
35
+ _check_randparams (rks, x, p)
36
+ @inbounds for i in eachindex (p)
37
+ rks[p[i]] = i
28
38
end
29
-
30
39
return rks
31
40
end
32
41
33
42
34
43
"""
35
- ordinalrank(x; lt = isless, rev::Bool = false)
44
+ ordinalrank(x; lt= isless, by=identity, rev::Bool= false, ... )
36
45
37
46
Return the [ordinal ranking](https://en.wikipedia.org/wiki/Ranking#Ordinal_ranking_.28.221234.22_ranking.29)
38
- ("1234" ranking) of an array. The `lt` keyword allows providing a custom "less
39
- than" function; use `rev=true` to reverse the sorting order.
40
- All items in `x` are given distinct, successive ranks based on their
41
- position in `sort(x; lt = lt, rev = rev)`.
47
+ ("1234" ranking) of an array. Supports the same keyword arguments as the `sort` function.
48
+ All items in `x` are given distinct, successive ranks based on their position
49
+ in the sorted vector.
42
50
Missing values are assigned rank `missing`.
43
51
"""
44
- ordinalrank (x:: AbstractArray ; lt = isless, rev :: Bool = false ) =
45
- ordinalrank! ( Array {Int} (undef, size (x)), x, sortperm (x; lt = lt, rev = rev) )
52
+ ordinalrank (x:: AbstractArray ; sortkwargs ... ) =
53
+ _rank (_ordinalrank!, x; sortkwargs ... )
46
54
47
55
48
56
# Competition ranking ("1224" ranking) -- resolve tied ranks using min
49
- function competerank ! (rks:: AbstractArray , x:: AbstractArray , p:: IntegerArray )
57
+ function _competerank ! (rks:: AbstractArray , x:: AbstractArray , p:: IntegerArray )
50
58
n = _check_randparams (rks, x, p)
51
59
52
- if n > 0
60
+ @inbounds if n > 0
53
61
p1 = p[1 ]
54
62
v = x[p1]
55
63
rks[p1] = k = 1
56
64
57
- i = 2
58
- while i <= n
65
+ for i in 2 : n
59
66
pi = p[i]
60
67
xi = x[pi ]
61
- if xi == v
62
- rks[pi ] = k
63
- else
64
- rks[pi ] = k = i
68
+ if xi != v
65
69
v = xi
70
+ k = i
66
71
end
67
- i += 1
72
+ rks[ pi ] = k
68
73
end
69
74
end
70
75
73
78
74
79
75
80
"""
76
- competerank(x; lt = isless, rev::Bool = false)
81
+ competerank(x; lt= isless, by=identity, rev::Bool= false, ... )
77
82
78
83
Return the [standard competition ranking](http://en.wikipedia.org/wiki/Ranking#Standard_competition_ranking_.28.221224.22_ranking.29)
79
- ("1224" ranking) of an array. The `lt` keyword allows providing a custom "less
80
- than" function; use `rev=true` to reverse the sorting order.
81
- Items that compare equal are given the same rank, then a gap is left
82
- in the rankings the size of the number of tied items - 1.
84
+ ("1224" ranking) of an array. Supports the same keyword arguments as the `sort` function.
85
+ Equal (*"tied"*) items are given the same rank, and the next rank comes after a gap
86
+ that is equal to the number of tied items - 1.
83
87
Missing values are assigned rank `missing`.
84
88
"""
85
- competerank (x:: AbstractArray ; lt = isless, rev :: Bool = false ) =
86
- competerank! ( Array {Int} (undef, size (x)), x, sortperm (x; lt = lt, rev = rev) )
89
+ competerank (x:: AbstractArray ; sortkwargs ... ) =
90
+ _rank (_competerank!, x; sortkwargs ... )
87
91
88
92
89
93
# Dense ranking ("1223" ranking) -- resolve tied ranks using min
90
- function denserank ! (rks:: AbstractArray , x:: AbstractArray , p:: IntegerArray )
94
+ function _denserank ! (rks:: AbstractArray , x:: AbstractArray , p:: IntegerArray )
91
95
n = _check_randparams (rks, x, p)
92
96
93
- if n > 0
97
+ @inbounds if n > 0
94
98
p1 = p[1 ]
95
99
v = x[p1]
96
100
rks[p1] = k = 1
97
101
98
- i = 2
99
- while i <= n
102
+ for i in 2 : n
100
103
pi = p[i]
101
104
xi = x[pi ]
102
- if xi == v
103
- rks[pi ] = k
104
- else
105
- rks[pi ] = (k += 1 )
105
+ if xi != v
106
106
v = xi
107
+ k += 1
107
108
end
108
- i += 1
109
+ rks[ pi ] = k
109
110
end
110
111
end
111
112
@@ -114,29 +115,27 @@ end
114
115
115
116
116
117
"""
117
- denserank(x)
118
+ denserank(x; lt=isless, by=identity, rev::Bool=false, ... )
118
119
119
120
Return the [dense ranking](http://en.wikipedia.org/wiki/Ranking#Dense_ranking_.28.221223.22_ranking.29)
120
- ("1223" ranking) of an array. The `lt` keyword allows providing a custom "less
121
- than" function; use `rev=true` to reverse the sorting order. Items that
122
- compare equal receive the same ranking, and the next subsequent rank is
121
+ ("1223" ranking) of an array. Supports the same keyword arguments as the `sort` function.
122
+ Equal items receive the same rank, and the next subsequent rank is
123
123
assigned with no gap.
124
124
Missing values are assigned rank `missing`.
125
125
"""
126
- denserank (x:: AbstractArray ; lt = isless, rev :: Bool = false ) =
127
- denserank! ( Array {Int} (undef, size (x)), x, sortperm (x; lt = lt, rev = rev) )
126
+ denserank (x:: AbstractArray ; sortkwargs ... ) =
127
+ _rank (_denserank!, x; sortkwargs ... )
128
128
129
129
130
130
# Tied ranking ("1 2.5 2.5 4" ranking) -- resolve tied ranks using average
131
- function tiedrank ! (rks:: AbstractArray , x:: AbstractArray , p:: IntegerArray )
131
+ function _tiedrank ! (rks:: AbstractArray , x:: AbstractArray , p:: IntegerArray )
132
132
n = _check_randparams (rks, x, p)
133
133
134
- if n > 0
134
+ @inbounds if n > 0
135
135
v = x[p[1 ]]
136
136
137
137
s = 1 # starting index of current range
138
- e = 2 # pass-by-end index of current range
139
- while e <= n
138
+ for e in 2 : n # e is pass-by-end index of current range
140
139
cx = x[p[e]]
141
140
if cx != v
142
141
# fill average rank to s : e-1
@@ -148,10 +147,9 @@ function tiedrank!(rks::AbstractArray, x::AbstractArray, p::IntegerArray)
148
147
s = e
149
148
v = cx
150
149
end
151
- e += 1
152
150
end
153
151
154
- # the last range (e == n+1)
152
+ # the last range
155
153
ar = (s + n) / 2
156
154
for i = s : n
157
155
rks[p[i]] = ar
@@ -161,33 +159,15 @@ function tiedrank!(rks::AbstractArray, x::AbstractArray, p::IntegerArray)
161
159
return rks
162
160
end
163
161
164
- # order (aka. rank), resolving ties using the mean rank
165
162
"""
166
- tiedrank(x)
163
+ tiedrank(x; lt=isless, by=identity, rev::Bool=false, ... )
167
164
168
165
Return the [tied ranking](http://en.wikipedia.org/wiki/Ranking#Fractional_ranking_.28.221_2.5_2.5_4.22_ranking.29),
169
166
also called fractional or "1 2.5 2.5 4" ranking,
170
- of an array. The `lt` keyword allows providing a custom "less
171
- than" function; use `rev=true` to reverse the sorting order.
172
- Items that compare equal receive the mean of the
173
- rankings they would have been assigned under ordinal ranking.
167
+ of an array. Supports the same keyword arguments as the `sort` function.
168
+ Equal (*"tied"*) items receive the mean of the ranks they would
169
+ have been assigned under the ordinal ranking (see [`ordinalrank`](@ref)).
174
170
Missing values are assigned rank `missing`.
175
171
"""
176
- tiedrank (x:: AbstractArray ; lt = isless, rev:: Bool = false ) =
177
- tiedrank! (Array {Float64} (undef, size (x)), x, sortperm (x; lt = lt, rev = rev))
178
-
179
- for (f, f!, S) in zip ([:ordinalrank , :competerank , :denserank , :tiedrank ],
180
- [:ordinalrank! , :competerank! , :denserank! , :tiedrank! ],
181
- [Int, Int, Int, Float64])
182
- @eval begin
183
- function $f (x:: AbstractArray{>: Missing} ; lt = isless, rev:: Bool = false )
184
- inds = findall (! ismissing, x)
185
- isempty (inds) && return missings ($ S, size (x))
186
- xv = disallowmissing (view (x, inds))
187
- sp = sortperm (xv; lt = lt, rev = rev)
188
- rks = missings ($ S, length (x))
189
- $ (f!)(view (rks, inds), xv, sp)
190
- rks
191
- end
192
- end
193
- end
172
+ tiedrank (x:: AbstractArray ; sortkwargs... ) =
173
+ _rank (_tiedrank!, x, Float64; sortkwargs... )
0 commit comments