当价值观之间存在联系时,如何获得无差距的排名?

问题描述 投票:0回答:8

当原始数据中存在平局时,是否有办法创建一个没有排名差距的排名(连续的整数排名值)?假设:

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()
函数实现此目的?

r
8个回答
16
投票

修改了 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
投票

“无循环”的方法是简单地将向量视为有序因子,然后将其转换为数字:

> 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
投票

我能想到一个快速的函数来做到这一点。对于 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

4
投票

尝试想别的办法

x <-  c(10,10,10,5,5,20,20)
as.numeric(as.factor(x))
[1] 2 2 2 1 1 3 3

4
投票

如果你不介意离开基地R:

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

数据:

x <- c(10, 10, 10, 5, 5, 20, 20)

3
投票

对于那些喜欢使用

dplyr
的人:

dense_rank(x)

[1] 2 2 2 1 1 3 3

2
投票

另一个函数可以做到这一点,但效率似乎很低。没有

for
循环,但我怀疑它比 Sacha 的建议更有效!

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

-1
投票

sort()
呢?

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

> sort(x) 
[1] 1 1 2 3 4 5
© www.soinside.com 2019 - 2024. All rights reserved.