tidyverse 计算每行跨多列的排名
tidyverse calculate ranking per row across several columns
我有以下数据框:
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))
我现在想计算我的三个 x 列中每行 的排名,并想将该结果存储到我的 dat
数据框中。
所以结果可以用两种方式存储:
a) 理想情况下,将有 4 个具有相应等级的新列或
b) 将有一个新的嵌套列,我可能需要以某种方式取消嵌套。
我尝试了以下至少给了我一个列表列。
dat %>%
rowwise() %>%
mutate(my_ranks = list(rank(c_across(starts_with("x")))))
但是当我尝试取消嵌套时,它会给我排名,但它是通过创建新行来实现的(即每个原始案例现在出现四次)。虽然我想我可以用 pivot_wider
以某种方式重塑这个结果,但遵循这条路线感觉不对。
有什么 better/easier 想法吗?谢谢
我想这是某种 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
我们可以使用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
使用 matrixStats
中的 rowRanks
可以更直接地完成
library(matrixStats)
nm1 <- names(dat)[-1]
dat[paste0('rank', nm1)] <- rowRanks(as.matrix(dat[nm1]), ties.method = 'average')
我有以下数据框:
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))
我现在想计算我的三个 x 列中每行 的排名,并想将该结果存储到我的 dat
数据框中。
所以结果可以用两种方式存储:
a) 理想情况下,将有 4 个具有相应等级的新列或
b) 将有一个新的嵌套列,我可能需要以某种方式取消嵌套。
我尝试了以下至少给了我一个列表列。
dat %>%
rowwise() %>%
mutate(my_ranks = list(rank(c_across(starts_with("x")))))
但是当我尝试取消嵌套时,它会给我排名,但它是通过创建新行来实现的(即每个原始案例现在出现四次)。虽然我想我可以用 pivot_wider
以某种方式重塑这个结果,但遵循这条路线感觉不对。
有什么 better/easier 想法吗?谢谢
我想这是某种 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
我们可以使用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
使用 matrixStats
rowRanks
可以更直接地完成
library(matrixStats)
nm1 <- names(dat)[-1]
dat[paste0('rank', nm1)] <- rowRanks(as.matrix(dat[nm1]), ties.method = 'average')