根据两个变量的值进行排名 - r

3

I have this dataframe:

   df<-data.frame(
      var1 = c(rep(c(rep(1,2), rep(2,3), rep(3,2), rep(4,1)),2), 1),
      var2 = c(rep(1,8), rep(2,8),3)
    )


df

    var1 var2
#1     1    1
#2     1    1
#3     2    1
#4     2    1
#5     2    1
#6     3    1
#7     3    1
#8     4    1
#9     1    2
#10    1    2
#11    2    2
#12    2    2
#13    2    2
#14    3    2
#15    3    2
#16    4    2
#17    1    3

我想创建一个第三个变量作为排名。如果行具有最低的var2数字,然后根据var1数字的低高程度进行排名。例如,具有var2 = 1和var1 = 1的第1行和第2行应该排名第1。而var2 = 2和var1 = 1的第9行和第10行应该排名第5。
如果我的数据按照var2和var1的升序排列,则使用我喜爱的R函数rle执行以下操作以获得所需的排名:
rle(df$var1)
N <- length(rle(df$var1)$lengths)
df$ranks  <- rep(1:N, rle(df$var1)$lengths)

df

    var1 var2 ranks
#1     1    1     1
#2     1    1     1
#3     2    1     2
#4     2    1     2
#5     2    1     2
#6     3    1     3
#7     3    1     3
#8     4    1     4
#9     1    2     5
#10    1    2     5
#11    2    2     6
#12    2    2     6
#13    2    2     6
#14    3    2     7
#15    3    2     7
#16    4    2     8
#17    1    3     9

这样可以实现,但是需要事先对df进行排序。我想要一种不需要这样做的解决方案。我觉得使用rank应该可以简单地一行代码实现,但我可能有盲点。感谢任何帮助。

编辑1:
-添加一个更大的示例以测试建议的答案

dput(df1)
df1 <- structure(list(var1 = c(1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 
3L, 3L, 3L, 3L, 3L, 4L, 4L, 4L, 4L, 4L, 5L, 5L, 5L, 5L, 5L, 7L, 
7L, 7L, 7L, 7L, 8L, 8L, 8L, 8L, 8L, 6L, 9L, 10L, 10L, 10L, 11L, 
12L, 12L, 12L, 13L, 14L, 14L, 14L, 14L, 15L, 16L, 16L, 16L, 16L, 
16L, 17L, 17L, 17L, 17L, 17L, 18L, 18L, 18L, 18L, 18L, 19L, 19L, 
20L, 20L, 21L, 22L, 22L, 22L, 22L, 22L, 23L, 23L, 23L, 23L, 23L, 
24L, 24L, 24L, 24L, 24L, 25L, 25L, 25L, 25L, 25L, 1L, 2L, 2L, 
2L, 2L, 4L, 5L, 5L, 5L, 5L, 6L, 6L, 6L, 6L, 6L, 7L, 7L, 7L, 7L, 
8L, 9L, 10L, 10L, 10L, 10L, 3L, 11L, 11L, 11L, 11L, 12L, 13L, 
13L, 13L, 13L, 14L, 14L, 14L, 14L, 14L, 15L, 15L, 15L, 15L, 15L, 
12L, 16L, 16L, 16L, 16L, 17L, 17L, 17L, 17L, 17L, 18L, 18L, 18L, 
18L, 18L, 19L, 19L, 19L, 19L, 19L, 20L, 20L, 20L, 20L, 21L, 22L, 
22L, 22L, 23L, 25L, 24L, 24L, 24L, 24L, 24L, 26L, 26L, 26L, 26L, 
26L, 27L, 27L, 27L, 27L, 27L, 1L, 2L, 2L, 2L, 2L, 3L, 3L, 3L, 
3L, 3L, 4L, 4L, 4L, 4L, 4L, 5L, 5L, 5L, 5L, 5L, 6L, 6L, 6L, 6L, 
6L, 7L, 7L, 7L, 7L, 7L, 8L, 9L, 9L, 9L, 9L, 10L, 10L, 10L, 10L, 
11L, 12L, 12L, 13L, 14L, 15L, 16L, 17L, 17L, 18L, 18L, 19L, 19L, 
19L, 19L, 20L, 21L, 21L, 21L, 21L, 21L, 22L, 22L, 22L, 22L, 22L, 
23L, 23L, 23L, 23L, 23L, 24L, 24L, 24L, 24L, 24L, 25L, 25L, 25L, 
25L, 25L, 26L, 26L, 26L, 27L, 27L, 28L, 28L, 28L, 28L, 28L, 1L, 
1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 3L, 3L, 3L, 3L, 3L, 4L, 4L, 
4L, 4L, 5L, 6L, 7L, 7L, 7L, 7L, 8L, 8L, 8L, 8L, 8L), var2 = c(1L, 
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 
2L, 2L, 2L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 
3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 
3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 
3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 
3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 
3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 4L, 4L, 4L, 
4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 
4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L, 4L), ranks = c(1L, 1L, 
1L, 1L, 1L, 12L, 12L, 12L, 12L, 12L, 19L, 19L, 19L, 19L, 19L, 
20L, 20L, 20L, 20L, 20L, 21L, 21L, 21L, 21L, 21L, 23L, 23L, 23L, 
23L, 23L, 24L, 24L, 24L, 24L, 24L, 22L, 25L, 2L, 2L, 2L, 3L, 
4L, 4L, 4L, 5L, 6L, 6L, 6L, 6L, 7L, 8L, 8L, 8L, 8L, 8L, 9L, 9L, 
9L, 9L, 9L, 10L, 10L, 10L, 10L, 10L, 11L, 11L, 13L, 13L, 14L, 
15L, 15L, 15L, 15L, 15L, 16L, 16L, 16L, 16L, 16L, 17L, 17L, 17L, 
17L, 17L, 18L, 18L, 18L, 18L, 18L, 26L, 37L, 37L, 37L, 37L, 47L, 
48L, 48L, 48L, 48L, 49L, 49L, 49L, 49L, 49L, 50L, 50L, 50L, 50L, 
51L, 52L, 27L, 27L, 27L, 27L, 46L, 28L, 28L, 28L, 28L, 29L, 30L, 
30L, 30L, 30L, 31L, 31L, 31L, 31L, 31L, 32L, 32L, 32L, 32L, 32L, 
29L, 33L, 33L, 33L, 33L, 34L, 34L, 34L, 34L, 34L, 35L, 35L, 35L, 
35L, 35L, 36L, 36L, 36L, 36L, 36L, 38L, 38L, 38L, 38L, 39L, 40L, 
40L, 40L, 41L, 43L, 42L, 42L, 42L, 42L, 42L, 44L, 44L, 44L, 44L, 
44L, 45L, 45L, 45L, 45L, 45L, 53L, 64L, 64L, 64L, 64L, 74L, 74L, 
74L, 74L, 74L, 75L, 75L, 75L, 75L, 75L, 76L, 76L, 76L, 76L, 76L, 
77L, 77L, 77L, 77L, 77L, 78L, 78L, 78L, 78L, 78L, 79L, 80L, 80L, 
80L, 80L, 54L, 54L, 54L, 54L, 55L, 56L, 56L, 57L, 58L, 59L, 60L, 
61L, 61L, 62L, 62L, 63L, 63L, 63L, 63L, 65L, 66L, 66L, 66L, 66L, 
66L, 67L, 67L, 67L, 67L, 67L, 68L, 68L, 68L, 68L, 68L, 69L, 69L, 
69L, 69L, 69L, 70L, 70L, 70L, 70L, 70L, 71L, 71L, 71L, 72L, 72L, 
73L, 73L, 73L, 73L, 73L, 81L, 81L, 81L, 81L, 81L, 82L, 82L, 82L, 
82L, 82L, 83L, 83L, 83L, 83L, 83L, 84L, 84L, 84L, 84L, 85L, 86L, 
87L, 87L, 87L, 87L, 88L, 88L, 88L, 88L, 88L)), .Names = c("var1", 
"var2", "ranks"), row.names = c(NA, -300L), class = "data.frame")

这个ranks变量是从这个建议的答案中获取的:

df1$ranks1 <- dense_rank(paste(df1$var2, df1$var1))

1
library(dplyr) ; dense_rank(paste(df$var2, df$var1))库(dplyr); dense_rank(paste(df $ var2,df $ var1)) - David Arenburg
@DavidArenburg 这不会按字典顺序而不是数字顺序排名吗?我认为 with(df, dense_rank(dense_rank(var2)+dense_rank(var1)/length(var1))) 可以工作,但一定有更简洁的方法来组合 var1var2 - user20637
@DavidArenburg 不是的。是 paste(或 paste0)将其转换为字符并强制按字典顺序排序。尝试 as.numeric(paste0(1.2, 3.1)) - user20637
var1var2是否总是整数?如果是,则应该可以使用dense_rank(as.numeric(paste0(df1$var2, df1$var1)))。虽然我开始认为只需排序(使用一些data.table函数,如setorder),然后排名将是最好的方法来完成此操作。 - David Arenburg
@DavidArenburg - 不好意思,这对我不起作用。例如,对于我上面给出的第二个示例,它似乎会为var1、var2、var3排名1-9,然后为var1、var2、var3排名10及以上等等。我想知道这是否是特定示例的特殊情况? - jalapic
显示剩余6条评论
1个回答

2
涉及paste[0]的解决方案仅在每个向量内的值为整数且位数固定时才有效。这是因为paste会转换为字符,并且:
  1. 字符(字典)排序与数字排序不同:rank(c(1 , 2, 11)); rank(as.character(c(1 , 2, 11)))
  2. 连接引入了歧义:paste0(2,12); paste0(21,2)
Peter Dalgaard在2011年发表了一篇相关文章http://r.789695.n4.nabble.com/Function-rank-for-data-frames-or-multiple-vectors-td3765685.html 现在忽略相同的行。请注意,rank(x) == order(order(x))并且order接受多个排序列,因此如果您不介意如何拆分相同的行,则order(order(df$var2, df$var1))可以完成工作。
这将根据其原始顺序拆分相同的行。有许多方法可以对相同的行进行排名http://en.wikipedia.org/wiki/Ranking#Strategies_for_assigning_rankings
在2011年,Peter Dalgaard建议使用ave(order(order(df$var2, df$var1)), df$var2, df$var1),它给出了维基百科所称的“分数排名”,并且在base::rank中是默认的ties.method="average"
您的示例是维基百科所谓的“密集排名”,它不可用于base::rank,但正如David Arenburg所评论的那样,由dplyr::dense_rank提供,因此您可以library(dyplr)并使用:dense_rank(ave(order(order(df$var2, df$var1)), df$var2, df$var1)) 查看dense_rank的代码只是:
function (x) 
{
    r <- rank(x)
    match(r, sort(unique(r)))
}

建议如果您不想加载dplyr,并且满意于使用2个语句创建另一个变量(例如r),则可以使用以下内容:
r <- ave(order(order(df$var2, df$var1)), df$var2, df$var1); match(r, sort(unique(r))) 编辑添加...
您可以通过认识到数据框实际上是一个列表来简化问题,因此以出现顺序对列进行排名:
dense_rank(ave(order(do.call(order, df)), df))

您正在按列进行反向排序,以出现的顺序为准。
dense_rank(ave(order(do.call(order, rev(df))), df))

或显式地指定列及其顺序

dense_rank(ave(order(do.call(order, df[,2:1])), df[,2:1]))

最后一个解决方案 dense_rank(ave(order(do.call(order, df[,2:1])), df[,2:1])) 很好用。看到你是如何分解这个问题的非常有用 - 谢谢。 - jalapic

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接