查找向量或列中第二个(第三个......)最高/最低值的*索引*的最快方法

时间:2011-04-06 15:36:35

标签: r

找到向量或列中第二个(第三个......)最高/最低值的索引的最快方法?

即。什么

sort(x,partial=n-1)[n-1]

max()

但是

which.max()

最佳,

Fastest way to find second (third...) highest/lowest value in vector or column

7 个答案:

答案 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
  }
}