tidyverse计算几列中每行的排名

问题描述

我有以下数据框:

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

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

a)理想情况下,将有4个新列,分别具有相应的等级或
b)将有一个我可能需要取消嵌套的新嵌套列。

我尝试了以下操作,至少可以给我一个列表列。

dat %>%
  rowwise() %>%
  mutate(my_ranks = list(rank(c_across(starts_with("x")))))

但是当我尝试取消嵌套时,它会给我排名,但是它会通过创建新行来实现(即,每个原始案例现在出现四次)。尽管我猜想我可以用pivot_wider重塑此结果,但遵循该路线还是很错误的。

有什么更好/更容易的主意吗?谢谢。

解决方法

我们可以使用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  

另一个选项是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  

使用rowRanks中的matrixStats可以更简单地完成

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

我想这是种tidyverse:

dat %>%
  bind_cols(as_tibble(`colnames<-`(t(apply(dat[-1],1,rank)),paste0("rank_x",1:3))))
#>   id x1 x2 x3 rank_x1 rank_x2 rank_x3
#> 1  a  1  4  2     1.0     3.0     2.0
#> 2  b  3  2  2     3.0     1.5     1.5
#> 3  c  5  6  5     1.5     3.0     1.5
#> 4  d  7  0  9     2.0     1.0     3.0