tidyverse 计算多列中每行的排名

des*_*hen 3 r rank dplyr

我有以下数据框:

dat <- data.frame(id = c("a", "b", "c", "d"),
                  x1 = c(1, 3, 5, 7),
                  x2 = c(4, 2, 6, 0),
                  x3 = c(2, 2, 5, 9))
Run Code Online (Sandbox Code Playgroud)

我现在想要计算三 x 列中每行的排名,并将该结果存储到我的dat数据框中。因此结果可以通过两种方式存储:

a) 理想情况下,将有 4 个具有各自等级的新列,或者
b) 将有一个新的嵌套列,我可能需要以某种方式取消嵌套。

我尝试了以下至少给了我一个列表列。

dat %>%
  rowwise() %>%
  mutate(my_ranks = list(rank(c_across(starts_with("x")))))
Run Code Online (Sandbox Code Playgroud)

但是当我尝试取消嵌套时,它会给我排名,但它是通过创建新行来实现的(即每个原始案例现在出现四次)。虽然我想我可以用某种方式重塑这个结果pivot_wider,但遵循这条路线感觉是错误的。

有更好/更简单的想法吗?谢谢。

akr*_*run 5

我们可以用unnest_wider

library(dplyr)
library(tidyr)
library(stringr)
dat %>%
   rowwise() %>%
   mutate(my_ranks = list(rank(c_across(starts_with("x"))))) %>%
   unnest_wider(c(my_ranks)) %>%
   rename_at(vars(starts_with("...")), ~ str_replace(., fixed("..."), "rank_x"))
# A tibble: 4 x 7
#  id       x1    x2    x3  rank_x1 rank_x2 rank_x3
#  <chr> <dbl> <dbl> <dbl>    <dbl>    <dbl>    <dbl>
#1 a         1     4     2      1        3        2  
#2 b         3     2     2      3        1.5      1.5
#3 c         5     6     5      1.5      3        1.5
#4 d         7     0     9      2        1        3  
Run Code Online (Sandbox Code Playgroud)

另一种选择是pmap/as_tibble_row

library(tibble)
library(purrr)
dat %>% 
     mutate(my_ranks = pmap(select(., starts_with('x')), ~ 
           as_tibble_row(rank(c(...)),
            .name_repair = ~ str_c('rank', seq_along(.))))) %>%
     unnest(c(my_ranks))
# A tibble: 4 x 7
#  id       x1    x2    x3 rank1 rank2 rank3
#  <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#1 a         1     4     2   1     3     2  
#2 b         3     2     2   3     1.5   1.5
#3 c         5     6     5   1.5   3     1.5
#4 d         7     0     9   2     1     3  
Run Code Online (Sandbox Code Playgroud)

rowRanks使用from可以更直接地完成matrixStats

library(matrixStats)
nm1 <- names(dat)[-1]
dat[paste0('rank', nm1)] <- rowRanks(as.matrix(dat[nm1]), ties.method = 'average')
Run Code Online (Sandbox Code Playgroud)