Как получить ранги без пропусков, когда есть связи между ценностями? - PullRequest
13 голосов
/ 06 февраля 2011

Когда есть связи в исходных данных, есть ли способ создать ранжирование без пробелов в рангах (последовательные, целочисленные значения ранга)?Предположим:

x <-  c(10, 10, 10, 5, 5, 20, 20)
rank(x)
# [1] 4.0 4.0 4.0 1.5 1.5 6.5 6.5

В этом случае желаемый результат будет:

my_rank(x)
[1] 2 2 2 1 1 3 3

Я играл со всеми опциями для опции ties.method (average, max, min, random), ни один из которых не предназначен для обеспечения желаемого результата.

Возможно ли добиться этого с помощью функции rank()?

Ответы [ 8 ]

16 голосов
/ 07 февраля 2011

Модифицированный раствор crayola , но с использованием match вместо merge:

x_unique <- unique(x)
x_ranks <- rank(x_unique)
x_ranks[match(x,x_unique)]

редактировать

или в одной строке, согласно комментарию @hadley:

match(x, sort(unique(x)))
9 голосов
/ 07 февраля 2011

«Бесконечный» способ сделать это - просто обработать вектор как упорядоченный коэффициент, а затем преобразовать его в числовой:

> as.numeric( ordered( c( 10,10,10,10, 5,5,5, 10, 10 ) ) )
[1] 2 2 2 2 1 1 1 2 2
> as.numeric( ordered( c(0.5,0.56,0.76,0.23,0.33,0.4) ))
[1] 4 5 6 1 2 3
> as.numeric( ordered( c(1,1,2,3,4,5,8,8) ))
[1] 1 1 2 3 4 5 6 6

Обновление: Другой способ, который кажется более быстрым, заключается в использовании findInterval и sort(unique()):

> x <- c( 10, 10, 10, 10, 5,5,5, 10, 10)
> findInterval( x, sort(unique(x)))
[1] 2 2 2 2 1 1 1 2 2

> x <- round( abs( rnorm(1000000)*10))
> system.time( z <- as.numeric( ordered( x )))
   user  system elapsed 
  0.996   0.025   1.021 
> system.time( z <- findInterval( x, sort(unique(x))))
   user  system elapsed 
  0.077   0.003   0.080 
4 голосов
/ 06 февраля 2011

Я могу придумать быструю функцию для этого. Это не оптимально для цикла for, но это работает:)

x=c(1,1,2,3,4,5,8,8)

foo <- function(x){
    su=sort(unique(x))
    for (i in 1:length(su)) x[x==su[i]] = i
    return(x)
}

foo(x)

[1] 1 1 2 3 4 5 6 6
2 голосов
/ 02 октября 2018

Если вы не против оставить базу-R:

library(data.table)
frank(x, ties.method = "dense")
[1] 2 2 2 1 1 3 3

data:

x <-  c(10, 10, 10, 5, 5, 20, 20)
2 голосов
/ 17 мая 2017

попробуй подумать о другом

x <-  c(10,10,10,5,5,20,20)
as.numeric(as.factor(x))
[1] 2 2 2 1 1 3 3
2 голосов
/ 07 февраля 2011

Еще одна функция, которая делает это, но кажется неэффективной.Петли for нет, но я сомневаюсь, что она более эффективна, чем предложение Саши!

x=c(1,1,2,3,4,5,8,8)
fancy.rank <- function(x) {
    x.unique <- unique(x)
    d1 <- data.frame(x=x)
    d2 <- data.frame(x=x.unique, rank(x.unique))
    merge(d1, d2, by="x")[,2]
}

fancy.rank(x)

[1] 1 1 2 3 4 5 6 6
0 голосов
/ 26 июня 2019

Для любителей dplyr:

dense_rank(x)

[1] 2 2 2 1 1 3 3
0 голосов
/ 06 февраля 2011

А как же sort()?

x <- c(1,1,2,3,4,5)
sort(x)

> sort(x) 
[1] 1 1 2 3 4 5
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...