IT

벡터 또는 열에서 두 번째(세 번째...) 가장 높은/낮은 값을 찾는 가장 빠른 방법

itgroup 2023. 7. 7. 18:57
반응형

벡터 또는 열에서 두 번째(세 번째...) 가장 높은/낮은 값을 찾는 가장 빠른 방법

R은 max와 min을 제공하지만 전체 벡터를 정렬한 다음 이 벡터에서 값 x를 선택하는 것 외에는 순서에서 다른 값을 찾는 정말 빠른 방법이 보이지 않습니다.

예를 들어 두 번째로 높은 값을 얻는 더 빠른 방법이 있습니까?

을 합니다.partialsort()인 경우: " 번째로높값경우":

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

기록을 위해 약간 느린 대안:

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

Rfast에는 사용자가 요청한 대로 정확히 수행하는 nth_element라는 함수가 있습니다.

또한 부분 정렬에 기반한 위의 방법은 k개의 최소값 찾기를 지원하지 않습니다.

업데이트(28/2/21) 패키지 키트를 사용하면 구현 속도가 빨라집니다(상위 n). https://stackoverflow.com/a/66367996/4729755, 를 참조하십시오.

고지 사항:as.numeric(예: Rfast::nth(as.numeric(1:10), 2))을 사용하여 우회할 수 있는 정수를 처리할 때 문제가 발생하며 Rfast의 다음 업데이트에서 해결됩니다.

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

x의 5번째로 큰 요소를 반환하는 동안

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

x의 5번째 작은 원소를 반환합니다.

가장 일반적인 답변과 비교하여 아래의 벤치마크를 제공합니다.

10,000개 숫자의 경우:

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

100만 개의 숫자:

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

Rob의 답변을 두 번째, 세 번째, 네 번째(등) 최대값을 찾는 데 사용할 수 있는 약간 더 일반적인 함수로 요약했습니다.

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)

다음은 벡터에서 N개의 가장 작은/가장 큰 값의 인덱스를 찾는 쉬운 방법입니다(예: N = 3).

N <- 3

N 최소 크기:

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

N 최대:

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

따라서 다음과 같이 값을 추출할 수 있습니다.

x[ndx]

n번째로 높은 값의 경우

sort(x, TRUE)[n]

여기 있습니다...키트가 확실한 승자입니다!

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::topn가지다hasna 한 번 더 뛰죠.

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

여기 제가 찾은 가장 간단한 방법이 있습니다.

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

먼저 max 요소를 제거한 다음 다른 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 

dplyr에는 n번째 함수가 있으며, 여기서 첫 번째 인수는 벡터이고 두 번째는 원하는 위치입니다.반복되는 요소도 마찬가지입니다.예:

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

두 번째로 큰 값 찾기:

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

[1] 17

최근 주어진 벡터에서 상위 N max/min 숫자의 인덱스를 반환하는 R 함수를 찾고 있을 때, 그런 함수가 없다는 것에 놀랐습니다.

그리고 이것은 매우 유사한 것입니다.

base:: order 기능을 이용한 브루트 포스 솔루션이 가장 쉬운 것 같습니다.

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

그러나 N 값이 벡터 x의 길이에 비해 상대적으로 작은 경우에는 가장 빠른 값이 아닙니다.

N이 정말 작으면 base::max 함수를 반복적으로 사용할 수 있으며 각 반복에서 찾은 값을 -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에서 가장 좋은 해결책은 부분 베이스::sort를 사용하는 것이라고 생각합니다.

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

그런 다음 위에서 정의한 함수의 결과에서 마지막(N번째) 항목을 선택할 수 있습니다.

참고: 위에서 정의한 기능은 예제에 불과합니다. 사용하려면 입력을 확인/검사해야 합니다(예:길이(x).

저는 http://palusga.cz/ ?p=18에서 매우 유사한 것(벡터의 상위 N max/min 값의 인덱스 가져오기)에 대한 작은 기사를 썼습니다. 위에서 정의한 유사한 함수의 벤치마크를 여기에서 찾을 수 있습니다.

head(sort(x),..)또는tail(sort(x),...)효과가 있어야 합니다.

입력 숫자 벡터 x에서 N번째로 작거나 큰 값의 인덱스를 찾습니다. 아래쪽 =아래에서 N번째를 원하는 경우 인수에서 TRUE 또는 아래=처음부터 N'th를 원한다면 FALSE입니다.N=1 및 하단=TRUE는 다음과 같습니다.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)
}
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-Chou에 도움이 되길 바랍니다.

다음으로 높은 값을 식별할 수 있습니다.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

사용할 수 있습니다.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개의 최대 숫자를 제공합니다.

언급URL : https://stackoverflow.com/questions/2453326/fastest-way-to-find-second-third-highest-lowest-value-in-vector-or-column

반응형