使用R语言中的两列数据对数据框进行排名

3

我是R语言的新手,正在尝试使用R语言中的两列数据对数据框进行排名,但碰到了困难。

数据的形式如下:

A B
1 1
2 1
2 1
4 4
5 3

我希望结果以以下形式呈现:
A B Rank
1 1 1
2 1 2
2 1 2
4 4 5
5 3 4

B排名第一,如果B值相等,则使用A进行排名。我认为我的问题与如何在R中同时按两个列对行进行排名?非常相似。我尝试了其中的答案,但这对我没有起作用。


4
我不太明白。你能详细解释一下你是如何得到排名列的吗?另外,为什么两个数据集中的第三行不同呢? - user2974951
1
我认为第二个示例表格中有一些错别字。列 A 以前有一个3(被2替换),列 B 以前有一个2(被1替换)。 - KamRa
1
有关不同连接方法的更广泛描述,请参见如何在R中模拟SQL的排名函数?。在那里,您还可以找到一个很好的data.table :: frank的描述(当您在多个列上进行排名时非常相关)。 - Henrik
4个回答

4
你可以按照B和A进行排序,赋予它一个分组ID,然后在这个分组ID上进行排名。
数据:
dt <- structure(list(A = c(1L, 2L, 2L, 4L, 5L), B = c(1L, 1L, 1L, 4L, 
3L)), row.names = c(NA, -5L), class = c("data.frame"
))

data.table

library(data.table)
setDT(dt)

setorder(dt, B, A)
dt[, Rank := .GRP, by = .(A, B)][, Rank := rank(Rank, ties.method = "min")]

dt
   A B Rank
1: 1 1    1
2: 2 1    2
3: 2 1    2
4: 5 3    4
5: 4 4    5

dyplr

library(dplyr)

dt %>% 
  arrange(B, A) %>%
  group_by(B, A) %>%
  mutate(Rank = cur_group_id()) %>%
  ungroup() %>%
  mutate(Rank = rank(Rank, ties.method = "min"))

# A tibble: 5 x 3
      A     B  Rank
  <int> <int> <int>
1     1     1     1
2     2     1     2
3     2     1     2
4     5     3     4
5     4     4     5

4
你可以使用 data.table::frankdplyr::min_rank:

data.table::frank

dt$Rank <- frank(dt, B, A, ties.method = "min")
dt
  A B Rank
1 1 1    1
2 2 1    2
3 2 1    2
4 4 4    5
5 5 3    4

dplyr::min_rank

mutate(dt, Rank = min_rank(paste(B,A)))
  A B Rank
1 1 1    1
2 2 1    2
3 2 1    2
4 4 4    5
5 5 3    4

数据

dt <- data.frame(A = c(1,2,2,4,5), B = c(1,1,1,4,3))

1
我之前也不知道frank函数,但是通过引用来使用它似乎是这样的方式:dt[, Rank := frank(.SD, ties.method = "min"), .SDcols = c("B", "A")] - Merijn van Tilborg
dplyr 解决方案中,如果 AB 的某些值是两位数,那么 paste 函数是否能够正确工作? - bill999

1
也许这个基于R的选项可以帮助解决问题。
transform(
  df,
  Rank = rank(A[order(B, A)], ties.method = "min")
)

这提供了

  A B Rank
1 1 1    1
2 2 1    2
3 2 1    2
4 4 4    5
5 5 3    4

0
我能想到的最简单的方法是使用dplyr中的一个名为arrange的函数,首先按B,然后按A排序,创建列的顺序作为排名,然后重新排列以模拟您的输出。
为了重复相同条目的排名,我们可以添加一个ifelse语句,该语句查看前一行并保留排名(如果此行具有相同的A和B值)。
以下是示例代码:
df <- data.frame(A = c(1,2,2,4,5),
                 B = c(1,1,1,4,3))

library(tidyverse)
df %>%
    arrange(B,A) %>%
    mutate(Rank = 1:n(),
           Rank = ifelse(A == lag(A, default = 0) & B == lag(B, default = 0), 
                         lag(Rank), Rank)) %>%
    arrange(A,B)
#>   A B Rank
#> 1 1 1    1
#> 2 2 1    2
#> 3 2 1    2
#> 4 4 4    5
#> 5 5 3    4

reprex package (v2.0.1)于2022年01月07日创建


1
但是原帖的排名被复制了2次。而你的代码给出了不同的结果。 - asd-tm
啊,是的,我没注意到。我会编辑一个补丁。 - csgroen

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