如果价值观之间存在联系,如何在没有差距的情况下获得排名?

时间:2011-02-06 19:54:54

标签: r

当原始数据中存在联系时,有没有办法在排名中创建无间隙的排名(连续,整数排名值)?假设:

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选项(averagemaxminrandom)的所有选项,其中没有一个是针对提供理想的结果。

是否可以使用rank()功能实现此功能?

8 个答案:

答案 0 :(得分:15)

已修改crayola solution但使用match代替merge

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

修改

根据@hadley的评论

或单行,

match(x, sort(unique(x)))

答案 1 :(得分:8)

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

> 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

更新:另一种方式,似乎更快,就是使用findIntervalsort(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 

答案 2 :(得分: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

答案 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

答案 4 :(得分:2)

尝试考虑另一种方式

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

答案 5 :(得分:2)

如果您不介意离开base-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)

答案 6 :(得分:0)

对于喜欢使用dplyr的人:

dense_rank(x)

[1] 2 2 2 1 1 3 3

答案 7 :(得分:-1)

sort()怎么样?

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

> sort(x) 
[1] 1 1 2 3 4 5