在矢量或列中找到第二(第三...)最高/最低值的最快方法

时间:2010-03-16 09:54:16

标签: r vector

R提供最大值和最小值,但除了对整个矢量进行排序而不是从此向量中选取值x之外,我没有看到在序列中找到另一个值的快速方法。

是否有更快的方法来获得第二高的值(例如)?

由于

16 个答案:

答案 0 :(得分:184)

使用partial的{​​{1}}参数。第二个最高值:

sort()

答案 1 :(得分:48)

稍微慢一点,只为记录​​:

x <- c(12.45,34,4,0,-234,45.6,4)
max( x[x!=max(x)] )
min( x[x!=min(x)] )

答案 2 :(得分:27)

我将Rob的答案包含在稍微更通用的功能中,可用于查找第2,第3,第4(等)max:

maxN <- function(x, N=2){
  len <- length(x)
  if(N>len){
    warning('N greater than length(x).  Setting N=length(x)')
    N <- length(x)
  }
  sort(x,partial=len-N+1)[len-N+1]
}

maxN(1:10)

答案 3 :(得分:15)

这是一种查找向量中N个最小值/最大值的索引的简单方法(N = 3的示例):

N <- 3

N最小:

ndx <- order(x)[1:N]

N最大:

ndx <- order(x, decreasing = T)[1:N]

因此您可以将值提取为:

x[ndx]

答案 4 :(得分:11)

Rfast 具有一个称为nth_element的函数,它可以完全满足您的要求,并且比上述所有实现都要快

上面讨论的基于部分排序的方法也不支持找到k个最小

Rfast::nth(x, 5, descending = T)

将返回x的第五大元素,而

Rfast::nth(x, 5, descending = F)

将返回x的第五个最小元素

以下是针对最受欢迎答案的基准。

对于1万个数字:

N = 10000
x = rnorm(N)

maxN <- function(x, N=2){
    len <- length(x)
    if(N>len){
        warning('N greater than length(x).  Setting N=length(x)')
        N <- length(x)
    }
    sort(x,partial=len-N+1)[len-N+1]
}

microbenchmark::microbenchmark(
    Rfast = Rfast::nth(x,5,descending = T),
    maxn = maxN(x,5),
    order = x[order(x, decreasing = T)[5]]
)

Unit: microseconds
  expr      min       lq      mean   median        uq       max neval
 Rfast  160.364  179.607  202.8024  194.575  210.1830   351.517   100
  maxN  396.419  423.360  559.2707  446.452  487.0775  4949.452   100
 order 1288.466 1343.417 1746.7627 1433.221 1500.7865 13768.148   100

使用10个百万号码:

N = 1e6
x = rnorm(N)

microbenchmark::microbenchmark(
    Rfast = Rfast::nth(x,5,descending = T),
    maxN = maxN(x,5),
    order = x[order(x, decreasing = T)[5]]
)

Unit: milliseconds
  expr      min        lq      mean   median        uq       max neval
 Rfast  89.7722  93.63674  114.9893 104.6325  120.5767  204.8839   100
  maxN 150.2822 207.03922  235.3037 241.7604  259.7476  336.7051   100
 order 930.8924 968.54785 1005.5487 991.7995 1031.0290 1164.9129   100

答案 5 :(得分:5)

对于第n个最高值,

sort(x, TRUE)[n]

答案 6 :(得分:3)

我发现首先删除max元素,然后以相当的速度执行另一次最大运行:

system.time({a=runif(1000000);m=max(a);i=which.max(a);b=a[-i];max(b)})
   user  system elapsed 
  0.092   0.000   0.659 

system.time({a=runif(1000000);n=length(a);sort(a,partial=n-1)[n-1]})
   user  system elapsed 
  0.096   0.000   0.653 

答案 7 :(得分:3)

这是我发现的最简单的方法,

num <- c(5665,1615,5154,65564,69895646)

num <- sort(num, decreasing = F)

tail(num, 1)                           # Highest number
head(tail(num, 2),1)                   # Second Highest number
head(tail(num, 3),1)                   # Third Highest number
head(tail(num, n),1)                   # Generl equation for finding nth Highest number

答案 8 :(得分:2)

给你... kit是明显的赢家!

N = 1e6
x = rnorm(N)

maxN <- function(x, N=2){
  len <- length(x)
  if(N>len){
    warning('N greater than length(x).  Setting N=length(x)')
    N <- length(x)
  }
  sort(x,partial=len-N+1)[len-N+1]
}

microbenchmark::microbenchmark(
  Rfast = Rfast::nth(x,5,descending = T),
  maxN = maxN(x,5),
  order = x[order(x, decreasing = T)[5]],
  kit = x[kit::topn(x, 5L,decreasing = T)[5L]]
) 
# Unit: milliseconds
# expr       min        lq     mean    median        uq        max neval
# Rfast 12.311168 12.473771 16.36982 12.702134 16.110779 102.749873   100
# maxN  12.922118 13.124358 17.49628 18.977537 20.053139  28.928694   100
# order 50.443100 50.926975 52.54067 51.270163 52.323116  66.561606   100
# kit    1.177202  1.216371  1.29542  1.240228  1.297286   2.771715   100

编辑:我忘了 kit::topnhasna 选项...让我们再运行一​​次。

microbenchmark::microbenchmark(
  Rfast = Rfast::nth(x,5,descending = T),
  maxN = maxN(x,5),
  order = x[order(x, decreasing = T)[5]],
  kit = x[kit::topn(x, 5L,decreasing = T)[5L]],
  kit2 = x[kit::topn(x, 5L,decreasing = T,hasna = F)[5L]],
  unit = "ms"
) 
# Unit: milliseconds
# expr       min        lq       mean     median        uq       max neval
# Rfast 13.194314 13.358787 14.7227116 13.4560340 14.551194 24.524105   100
# maxN   7.378960  7.527661 10.0747803  7.7119715 12.217756 67.409526   100
# order 50.088927 50.488832 52.4714347 50.7415680 52.267003 70.062662   100
# kit    1.180698  1.217237  1.2975441  1.2429790  1.278243  3.263202   100
# kit2   0.842354  0.876329  0.9398055  0.9109095  0.944407  2.135903   100

答案 9 :(得分:1)

当我最近寻找 R 函数返回给定向量中最高N max / min数的索引时,我很惊讶没有这样的函数。

这是非常相似的。

使用 base :: order 功能的强力解决方案似乎是最简单的。

topMaxUsingFullSort <- function(x, N) {
  sort(x, decreasing = TRUE)[1:min(N, length(x))]
}

但是,如果 N 值与矢量 x 的长度相比相对较小,则不是最快的。

另一方面,如果 N 非常小,您可以迭代使用 base :: whichMax 函数,并且在每次迭代中,您可以通过替换找到的值-Inf

# the input vector 'x' must not contain -Inf value 
topMaxUsingWhichMax <- function(x, N) {
  vals <- c()
  for(i in 1:min(N, length(x))) {
    idx      <- which.max(x)
    vals     <- c(vals, x[idx]) # copy-on-modify (this is not an issue because idxs is relative small vector)
    x[idx]   <- -Inf            # copy-on-modify (this is the issue because data vector could be huge)
  }
  vals
}

我相信你会看到问题--R的复制修改性质。所以这对非常非常小的N(1,2,3)表现得更好,但是对于更大的N值它会迅速减速。而且你正在迭代向量 x N 次的所有元素。

我认为干净 R 的最佳解决方案是使用部分 base :: sort

topMaxUsingPartialSort <- function(x, N) {
  N <- min(N, length(x))
  x[x >= -sort(-x, partial=N)[N]][1:N]
}

然后你可以从上面的函数defiend的结果中选择最后一个( N )项。

注意:上面定义的函数只是示例 - 如果要使用它们,则必须检查/完整性输入(例如 N&gt; length(x))。

我在http://palusga.cz/?p=18写了一篇关于非常类似的东西的小文章(得到矢量的前N个最大值/最小值的索引) - 你可以在这里找到我上面定义的类似函数的一些基准。

答案 10 :(得分:1)

head(sort(x),..)tail(sort(x),...)应该有效

答案 11 :(得分:0)

topn = function(vector, n){
  maxs=c()
  ind=c()
  for (i in 1:n){
    biggest=match(max(vector), vector)
    ind[i]=biggest
    maxs[i]=max(vector)
    vector=vector[-biggest]
  }
  mat=cbind(maxs, ind)
  return(mat)
}

此函数将返回一个前n个值及其索引的矩阵。 希望能帮助到你 VDevi-周

答案 12 :(得分:0)

这将找到输入数值向量x中第N个最小值或最大值的索引。如果你想从底部得到N',则在参数中设置bottom = TRUE,如果你想要从顶部得到N',则设置bottom = FALSE。 N = 1,bottom = TRUE等于which.min,N = 1,bottom = FALSE等于which.max。

FindIndicesBottomTopN <- function(x=c(4,-2,5,-77,99),N=1,bottom=FALSE)
{

  k1 <- rank(x)
  if(bottom==TRUE){
    Nindex <- which(k1==N)
    Nindex <- Nindex[1]
  }

  if(bottom==FALSE){
    Nindex <- which(k1==(length(x)+1-N))
    Nindex <- Nindex[1]
  }

  return(Nindex)
}

答案 13 :(得分:0)

dplyr具有函数nth,其中第一个参数是向量,第二个参数是您想要的位置。这也适用于重复元素。 例如:

x = c(1,2, 8, 16, 17, 20, 1, 20)

找到第二大值:

 nth(unique(x),length(unique(x))-1)

[1] 17

答案 14 :(得分:-1)

您可以使用cummax()识别下一个更高的值。例如,如果您想要每个新的较高值的位置,可以将cummax()值的向量传递给diff()函数,以标识cummax()值更改的位置。说我们有载体

v <- c(4,6,3,2,-5,6,8,12,16)
cummax(v) will give us the vector
4  6  6  6  6  6  8 12 16

现在,如果您想在cummax()找到更改的位置,您有很多选项,我倾向于使用sign(diff(cummax(v)))。由于diff(),您必须调整丢失的第一个元素。向量v的完整代码为:

which(sign(diff(cummax(v)))==1)+1

答案 15 :(得分:-2)

您可以使用sort关键字,如下所示:

sort(unique(c))[1:N]

示例:

c <- c(4,2,44,2,1,45,34,2,4,22,244)
sort(unique(c), decreasing = TRUE)[1:5]

将给出前5个最大数字。