当原始数据中存在联系时,有没有办法在排名中创建无间隙的排名(连续,整数排名值)?假设:
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()
功能实现此功能?
答案 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
更新:另一种方式,似乎更快,就是使用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
答案 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