如何用data.table实现同分同排名且跳过占用位次的真实排名?
用data.table实现同分同排名且跳过占用位次的排名
嘿,我来帮你搞定这个排名需求!你想要的这种同分同排名、同时跳过相同成绩占用位次的排名(也叫竞争排名),确实不能直接用.GRP——因为.GRP只会生成连续的分组序号。不过用data.table可以通过结合分组大小和累计求和轻松实现,下面给你两种简洁的方法:
方法一:先生成排名键再合并
这种方法逻辑清晰,先单独计算每个等级对应的排名,再关联回原数据表:
library(data.table) DT <- data.table(GRADE = c("A","B","B","C",rep("D",4))) # 1. 按等级分组统计人数,排序后计算每个等级的排名 rank_key <- DT[, .N, by = GRADE][order(GRADE)][, RANK := cumsum(shift(N, fill = 0)) + 1] # 2. 将排名关联回原数据表 DT[rank_key, on = "GRADE", RANK := i.RANK] # 查看结果 DT
运行后得到的结果完全符合你的预期:
GRADE RANK 1: A 1 2: B 2 3: B 2 4: C 4 5: D 5 6: D 5 7: D 5 8: D 5
方法二:链式一步完成
如果喜欢更紧凑的写法,可以把逻辑放到一个链式操作里,不用单独生成中间表:
DT[, RANK := { # 内部计算每个等级的排名 rank_dt <- .SD[, .N, by = GRADE][order(GRADE)][, RANK := cumsum(shift(N, fill = 0)) + 1] # 匹配当前行的等级对应的排名 rank_dt[.SD, on = "GRADE", x.RANK] }]
关键逻辑解释
这里的核心是cumsum(shift(N, fill = 0)) + 1:
.N是每个等级的学生人数shift(N, fill = 0)会把每个等级的人数往前偏移一位,第一个等级的偏移值填充为0cumsum()计算前面所有等级的总人数,加1就是当前等级的起始排名(也就是该等级所有学生的排名)
内容的提问来源于stack exchange,提问作者Grec001
相关产品推荐
相关产品推荐

