Respostas:
Use o partial
argumento de sort()
. Para o segundo valor mais alto:
n <- length(x)
sort(x,partial=n-1)[n-1]
sort(x, TRUE)[2]
descrito na resposta de @ Abrar, além de não satisfazer a restrição da pergunta?
Error in sort.int(x, na.last = na.last, decreasing = decreasing, ...) : index 4705 outside bounds
Alguma idéia de qual pode ser o problema? Alguns detalhes: Meu x é um vetor numérico de comprimento 4706 com alguns NA
s nos dados. Tentei obter o segundo valor mais alto do vetor usando exatamente o mesmo código sugerido pelo @RobHyndman.
decreasing
argumento não seja compatível com a classificação parcial, você pode sempre -sort(-x, partial=n-1)[n-1]
; é logicamente a mesma coisa e leva consideravelmente menos tempo que sort(x, decreasing=TRUE)[n-1]
.
Alternativa um pouco mais lenta, apenas para os registros:
x <- c(12.45,34,4,0,-234,45.6,4)
max( x[x!=max(x)] )
min( x[x!=min(x)] )
max(x[-which.max(x)])
Coloquei a resposta de Rob em uma função um pouco mais geral, que pode ser usada para encontrar o 2º, 3º, 4º (etc.) máximo:
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)
maxN(1:10, 1:3)
(eu teria definir o N padrão a 1)
Rfast tem uma função chamada nth_element que faz exatamente o que você pede e é mais rápida que todas as implementações discutidas acima
Além disso, os métodos discutidos acima, baseados em classificação parcial, não suportam encontrar os k menores valores
Rfast::nth(x, 5, descending = T)
Retornará o quinto maior elemento de x, enquanto
Rfast::nth(x, 5, descending = F)
Retornará o quinto elemento menor de x
Referências abaixo em relação às respostas mais populares.
Para 10 mil números:
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
Para 1 milhão de números:
N = 1e6 #evaluates to 1 million
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
Rfast::nth
pode retornar vários elementos (por exemplo, 8º e 9º maiores elementos), bem como os índices desses elementos.
Aqui está uma maneira fácil de encontrar os índices de N menores / maiores valores em um vetor (exemplo para N = 3):
N <- 3
N Menor:
ndx <- order(x)[1:N]
N Maior:
ndx <- order(x, decreasing = T)[1:N]
Então você pode extrair os valores como:
x[ndx]
Para o enésimo valor mais alto,
sort(x, TRUE)[n]
Descobri que remover o elemento max primeiro e depois executar outro max é executado em velocidade comparável:
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
Aqui está a maneira mais simples que encontrei,
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
Recentemente, quando eu estava procurando por uma função R retornando índices dos principais números N max / min em um determinado vetor, fiquei surpreso por não haver essa função.
E isso é algo muito semelhante.
A solução de força bruta usando a função base :: order parece ser a mais fácil.
topMaxUsingFullSort <- function(x, N) {
sort(x, decreasing = TRUE)[1:min(N, length(x))]
}
Mas não é o mais rápido, caso o valor de N seja relativamente pequeno comparado ao comprimento do vetor x .
Por outro lado, se N é realmente pequeno, você pode usar a função base :: whichMax iterativamente e em cada iteração você pode substituir o valor encontrado por -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
}
Acredito que você veja o problema - a natureza de copiar na modificação de R. Portanto, isso terá um desempenho melhor para N muito muito muito pequeno (1,2,3), mas diminuirá rapidamente para valores de N maiores. E você está iterando sobre todos os elementos no vetor x N vezes.
Eu acho que a melhor solução no R limpo é usar parcial base :: sort .
topMaxUsingPartialSort <- function(x, N) {
N <- min(N, length(x))
x[x >= -sort(-x, partial=N)[N]][1:N]
}
Depois, você pode selecionar o último ( N item de th) a partir do resultado das funções defiend acima.
Nota: as funções definidas acima são apenas exemplos - se você quiser usá-las, deverá verificar as entradas / sanidade (por exemplo, N> length (x) ).
Escrevi um pequeno artigo sobre algo muito semelhante (obtenha índices dos principais valores máximos de N / min de um vetor) em http://palusga.cz/?p=18 - você pode encontrar aqui alguns benchmarks de funções semelhantes que defini acima.
head(sort(x),..)
ou tail(sort(x),...)
deve funcionar
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)
}
essa função retornará uma matriz com os n valores superiores e seus índices. espero que ajude VDevi-Chou
Isso localizará o índice do enésimo menor ou maior valor no vetor numérico de entrada x. Defina bottom = TRUE nos argumentos se você quiser o N'th do fundo, ou bottom = FALSE se você quiser o N'th do topo. N = 1 e inferior = TRUE é equivalente a qual.min, N = 1 e inferior = FALSE é equivalente a qual.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)
}
O dplyr tem a função enésima, onde o primeiro argumento é o vetor e o segundo é o local que você deseja. Isso vale para repetir elementos também. Por exemplo:
x = c(1,2, 8, 16, 17, 20, 1, 20)
Encontrando o segundo maior valor:
nth(unique(x),length(unique(x))-1)
[1] 17
x[[order(order_by)[[n]]]]
- portanto, é necessário classificar todo o vetor. Portanto, não será tão rápido quanto a resposta aceita.
sort
com o parcial = argumento (que muda tudo)
dplyr::nth()
? bench::mark(max(x[-which.max(x)]), x[[order(-x)[[2]]]] )
, nth()
parece quase 10 vezes mais lento, onde length(x)
são 3 milhões.
Você pode identificar o próximo valor mais alto com cummax()
. Se você deseja a localização de cada novo valor mais alto, por exemplo, pode passar seu vetor de cummax()
valores para a diff()
função para identificar os locais nos quais o cummax()
valor foi alterado. diga que temos o vetor
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
Agora, se você deseja encontrar o local de uma alteração, cummax()
tem muitas opções que eu costumo usar sign(diff(cummax(v)))
. Você deve ajustar o primeiro elemento perdido por causa de diff()
. O código completo para vetor v
seria:
which(sign(diff(cummax(v)))==1)+1
Você pode usar a sort
palavra - chave assim:
sort(unique(c))[1:N]
Exemplo:
c <- c(4,2,44,2,1,45,34,2,4,22,244)
sort(unique(c), decreasing = TRUE)[1:5]
dará os 5 primeiros números máximos.
topn
função que é mais rápida quesort
,order
enth
. Veja a documentação.