找到向量或列中第二个(第三个......)最高/最低值的索引的最快方法?
即。什么
sort(x,partial=n-1)[n-1]
是
max()
但是
which.max()
最佳,
Fastest way to find second (third...) highest/lowest value in vector or column
答案 0 :(得分:11)
一种可能的途径是使用index.return
参数sort
。我不确定这是否最快。
set.seed(21)
x <- rnorm(10)
ind <- 2
sapply(sort(x, index.return=TRUE), `[`, length(x)-ind+1)
# x ix
# 1.746222 3.000000
答案 1 :(得分:10)
编辑2:
正如约书亚所指出的那样,当你在最大值上有一个平局时,没有一个给定的解决方案实际上是正确的,所以:
X <- c(11:19,19)
n <- length(unique(X))
which(X == sort(unique(X),partial=n-1)[n-1])
然后正确地做到这一点的最快方法。我删除了订单方式,因为那个方法不起作用而且速度慢很多,所以根据OP不是一个好的答案。
指出我们遇到的问题:
> X <- c(11:19,19)
> n <- length(X)
> which(X == sort(X,partial=n-1)[n-1])
[1] 9 10 #which is the indices of the double maximum 19
> n <- length(unique(X))
> which(X == sort(unique(X),partial=n-1)[n-1])
[1] 8 # which is the correct index of 18
有效解决方案的时间安排:
> x <- runif(1000000)
> ind <- 2
> n <- length(unique(x))
> system.time(which(x == sort(unique(x),partial=n-ind+1)[n-ind+1]))
user system elapsed
0.11 0.00 0.11
> system.time(sapply(sort(unique(x), index.return=TRUE), `[`, n-ind+1))
user system elapsed
0.69 0.00 0.69
答案 2 :(得分:5)
库 Rfast 已实现了带有返回索引选项的第n个元素函数,这似乎比讨论的所有其他实现都要快。
x <- runif(1e+6)
ind <- 2
microbenchmark::microbenchmark(
Rfast = Rfast::nth(x,ind,descending = T,index.return = T),
order = order(x, decreasing = TRUE)[ind],
richie = which_nth_highest_richie(x,ind),
joris = which_nth_highest_joris(x,ind))
Unit: milliseconds
expr min lq mean median uq max neval
Rfast 22.89945 26.03551 31.61163 26.70668 32.07650 105.0016 100
order 113.54317 116.49898 122.97939 119.44496 124.63646 170.4589 100
richie 26.69556 27.93143 38.74055 36.16341 44.10246 116.7192 100
joris 126.52276 138.60153 151.49343 146.55747 155.60709 324.8605 100
答案 3 :(得分:4)
方法:将所有最大值设置为-Inf
,然后找到最大值的索引。无需排序。
X <- runif(1e7)
system.time(
{
X[X == max(X)] <- -Inf
which(X == max(X))
})
与领带合作非常快。
如果你能保证没有联系,那么更快的版本就是
system.time(
{
X[which.max(X)] <- -Inf
which.max(X)
})
编辑:正如Joris所提到的,这种方法不能很好地发现第三,第四等最高值。
which_nth_highest_richie <- function(x, n)
{
for(i in seq_len(n - 1L)) x[x == max(x)] <- -Inf
which(x == max(x))
}
which_nth_highest_joris <- function(x, n)
{
ux <- unique(x)
nux <- length(ux)
which(x == sort(ux, partial = nux - n + 1)[nux - n + 1])
}
使用x <- runif(1e7)
和n = 2
,Richie获胜
system.time(which_nth_highest_richie(x, 2)) #about half a second
system.time(which_nth_highest_joris(x, 2)) #about 2 seconds
对于n = 100
,Joris获胜
system.time(which_nth_highest_richie(x, 100)) #about 20 seconds, ouch!
system.time(which_nth_highest_joris(x, 100)) #still about 2 seconds
他们花费相同时间的平衡点约为n = 10
。
答案 4 :(得分:3)
没有联系 which()
可能是你的朋友。将sort()
解决方案的输出与which()
结合使用,以找到与sort()
步骤的输出匹配的索引。
> set.seed(1)
> x <- sample(1000, 250)
> sort(x,partial=n-1)[n-1]
[1] 992
> which(x == sort(x,partial=n-1)[n-1])
[1] 145
领带处理如果存在联系并且关系是第i个最大或更大的值,则上述解决方案无法正常工作(并且无意)。我们需要在对这些值进行排序之前采用向量的唯一值,然后上述解决方案才有效:
> set.seed(1)
> x <- sample(1000, 1000, replace = TRUE)
> length(unique(x))
[1] 639
> n <- length(x)
> i <- which(x == sort(x,partial=n-1)[n-1])
> sum(x > x[i])
[1] 0
> x.uni <- unique(x)
> n.uni <- length(x.uni)
> i <- which(x == sort(x.uni, partial = n.uni-1)[n.uni-1])
> sum(x > x[i])
[1] 2
> tail(sort(x))
[1] 994 996 997 997 1000 1000
order()
在这里也很有用:
> head(ord <- order(x, decreasing = TRUE))
[1] 220 145 209 202 211 163
所以这里的解决方案ord[2]
是x
的第二高/最大元素的索引。
一些时间:
> set.seed(1)
> X <- sample(1e7, 1e7)
> system.time({n <- length(X); which(X == sort(X, partial = n-1)[n-1])})
user system elapsed
0.319 0.058 0.378
> system.time({ord <- order(X, decreasing = TRUE); ord[2]})
user system elapsed
14.578 0.084 14.708
> system.time({order(X, decreasing = TRUE)[2]})
user system elapsed
14.647 0.084 14.779
但是当链接的帖子出现并且上面的时间显示时,order()
要慢得多,但两者都提供相同的结果:
> all.equal(which(X == sort(X, partial = n-1)[n-1]),
+ order(X, decreasing = TRUE)[2])
[1] TRUE
对于领带处理版本:
foo <- function(x, i) {
X <- unique(x)
N <- length(X)
i <- i-1
which(x == sort(X, partial = N-i)[N-i])
}
> system.time(foo(X, 2))
user system elapsed
1.249 0.176 1.454
所以额外的步骤会使这个解决方案慢一点,但它仍然与order()
竞争激烈。
答案 5 :(得分:1)
使用Zach给出的maxN函数find the next max value并使用arr.ind = TRUE的哪个()。
其中(x == maxN(x,4),arr.ind = TRUE)
使用arr.ind也会在上述任何解决方案中返回索引位置并简化代码。
答案 6 :(得分:0)
这是我在向量中找到前N个最高值的索引的解决方案(不完全是OP想要的,但这可能对其他人有帮助)
index.top.N = function(xs, N=10){
if(length(xs) > 0) {
o = order(xs, na.last=FALSE)
o.length = length(o)
if (N > o.length) N = o.length
o[((o.length-N+1):o.length)]
}
else {
0
}
}