我的目标是编写一个函数take_by_rank
base::subset
或dplyr
动词; -foo
表示“foo
的最大值获得最低等级”; n
个最高或最低行,这是为每个选定变量计算的排名之和。我对学习最新dplyr way和寻找替代方法感兴趣,即对包选择没有限制(纯base
或data.table
可能?)。
我目前的解决方案是
library(data.table)
library(dplyr)
library(rlang)
take_by_rank <- function(df, ..., n = 100) {
selected_vars <- quos(...)
if (!length(selected_vars))
stop("No variables to rank!")
prefix <- ".rank_"
for (i in seq_along(selected_vars)) {
rank_name <- paste0(prefix, quo_name(selected_vars[[i]]))
df <- df %>%
mutate(!!rank_name := frankv(!!selected_vars[[i]]))
}
df %>%
mutate(TotalRank = rowSums(select(df, starts_with(prefix)))) %>%
arrange(TotalRank) %>%
top_n(n, -TotalRank)
}
似乎没关系,但也许我错过了一些更简单的事情。如果有办法替换for循环,那也很好。
用法示例(供参考)
take_by_rank(mtcars, mpg, qsec, n = 3)
mpg cyl disp hp drat wt qsec vs am gear carb .rank_mpg .rank_qsec TotalRank
1 13.3 8 350 245 3.73 3.84 15.41 0 0 3 4 3 3 6
2 15.0 8 301 335 3.54 3.57 14.60 0 1 5 8 6 2 8
3 14.3 8 360 245 3.21 3.57 15.84 0 0 3 4 4 5 9
take_by_rank(mtcars, mpg, qsec, n = -3)
mpg cyl disp hp drat wt qsec vs am gear carb .rank_mpg .rank_qsec TotalRank
1 22.8 4 140.8 95 3.92 3.150 22.90 1 0 4 2 24.5 32 56.5
2 32.4 4 78.7 66 4.08 2.200 19.47 1 1 4 1 31.0 27 58.0
3 33.9 4 71.1 65 4.22 1.835 19.90 1 1 4 1 32.0 28 60.0
take_by_rank(mtcars, mpg, -qsec, n = 3)
mpg cyl disp hp drat wt qsec vs am gear carb .rank_mpg .rank_-qsec TotalRank
1 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1 14.0 2 16.0
2 10.4 8 472 205 2.93 5.250 17.98 0 0 3 4 1.5 15 16.5
3 10.4 8 460 215 3.00 5.424 17.82 0 0 3 4 1.5 16 17.5
答案 0 :(得分:1)
由于Alex P也建议您可以使用mutate_at()
删除for循环,然后我们可以将该函数重写为:
take_by_rank <- function(df, ..., n = 100) {
selected_vars <- quos(...)
if (!length(selected_vars))
stop("No variables to rank!")
df <- df %>%
mutate_at(selected_vars, funs(rank = frankv)) %>%
mutate(TotalRank = rowSums(select(., ends_with("_rank")))) %>%
arrange(TotalRank) %>%
top_n(n, -TotalRank)
}
这会将frankv
应用于所有选定的变量,并添加后缀为_rank的新列。我还更改了select语句以引用管道data.frame。如果您希望Totalrank计算具有完整的变量名称匹配,则可以使用。
take_by_rank_matching <- function(df, ..., n = 100) {
selected_vars <- quos(...)
if (!length(selected_vars))
stop("No variables to rank!")
df <- df %>%
mutate_at(selected_vars, funs(rank = frankv)) %>%
mutate(TotalRank = rowSums(
select_at(., unlist(lapply(selected_vars,
function(x)
paste0(quo_label(x), "_rank")))))) %>%
arrange(TotalRank) %>%
top_n(n, -TotalRank)
}
虽然我认为可能会有一种更清洁的方式。
答案 1 :(得分:1)
您可以将这些点传递给another property
,然后再将其传递给myArray.filter(x => x.id === input).map(x => x.anotherproperty)
vars()
这相当于将点传递到mutate_at()
然后传递给mutate_at(df, vars(...), myfuns)
:
tidyselect::vars_select()
答案 2 :(得分:0)
正如您所指出的那样,使用mutate_at
会导致无法(或非常难)使用-foo
行为。
我建议你这个解决方案。它与你所做的并没有太大的不同
我使用for-loop
更改了purrr::map
,并简化了total_rank
的创建。
library(tidyverse)
# ....
library(rlang)
# ....
take_by_rank <- function(df, ..., n = 100) {
# original quosures
selected_vars <- quos(...)
if (!length(selected_vars))
stop("No variables to rank!")
suffixed_vars <- map(selected_vars, ~ {
paste0(quo_name(.x), '_rank') %>%
as.name() %>%
as_quosure()
})
selected_vars %>%
map( ~ {
rank_name <- paste0(quo_name(.x), '_rank')
df %>% # or whatever rank function you want
mutate(!!rank_name := dense_rank(!!.x))
}) %>%
reduce(full_join) %>%
mutate(total_rank = '+'(!!!suffixed_vars)) %>% # !!! = unquote and splice
top_n(n, -total_rank)
}
take_by_rank(mtcars, mpg, qsec, n = 3)
#> Joining, by = c("mpg", "cyl", "disp", "hp", "drat", "wt", "qsec", "vs", "am", "gear", "carb")
#> mpg cyl disp hp drat wt qsec vs am gear carb mpg_rank qsec_rank
#> 1 14.3 8 360 245 3.21 3.57 15.84 0 0 3 4 3 5
#> 2 13.3 8 350 245 3.73 3.84 15.41 0 0 3 4 2 3
#> 3 15.0 8 301 335 3.54 3.57 14.60 0 1 5 8 5 2
#> total_rank
#> 1 8
#> 2 5
#> 3 7
take_by_rank(mtcars, mpg, qsec, n = -3)
#> Joining, by = c("mpg", "cyl", "disp", "hp", "drat", "wt", "qsec", "vs", "am", "gear", "carb")
#> mpg cyl disp hp drat wt qsec vs am gear carb mpg_rank qsec_rank
#> 1 22.8 4 140.8 95 3.92 3.150 22.90 1 0 4 2 19 30
#> 2 32.4 4 78.7 66 4.08 2.200 19.47 1 1 4 1 24 25
#> 3 33.9 4 71.1 65 4.22 1.835 19.90 1 1 4 1 25 26
#> total_rank
#> 1 49
#> 2 49
#> 3 51
take_by_rank(mtcars, mpg, -qsec, n = 3)
#> Joining, by = c("mpg", "cyl", "disp", "hp", "drat", "wt", "qsec", "vs", "am", "gear", "carb")
#> mpg cyl disp hp drat wt qsec vs am gear carb mpg_rank -qsec_rank
#> 1 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1 12 2
#> 2 10.4 8 472 205 2.93 5.250 17.98 0 0 3 4 1 14
#> 3 10.4 8 460 215 3.00 5.424 17.82 0 0 3 4 1 15
#> total_rank
#> 1 14
#> 2 15
#> 3 16
take_by_rank(mtcars, mpg, n = 3)
#> mpg cyl disp hp drat wt qsec vs am gear carb mpg_rank total_rank
#> 1 10.4 8 472 205 2.93 5.250 17.98 0 0 3 4 1 1
#> 2 10.4 8 460 215 3.00 5.424 17.82 0 0 3 4 1 1
#> 3 13.3 8 350 245 3.73 3.840 15.41 0 0 3 4 2 2