[英]dplyr'ish approach to simple subset/summarise function
提供的 function 實現了以下功能:
base
方法summarise_filtered <-
function(df,
subset_arg,
summary_fun = c("min", "max", "median"),
select_col) {
summary_fun <- match.arg(summary_fun)
sbst_vals <-
subset.data.frame(
df,
subset = eval(parse(text = subset_arg)),
drop = TRUE,
select = eval(parse(text = select_col))
)
do.call(match.fun(summary_fun), list(sbst_vals))
}
summarise_filtered(mtcars, "am == 1", "min", "cyl")
# [1] 4
summarise_filtered(mtcars, "am == 1", "max", "cyl")
# [1] 8
我有興趣使用dplyr
pipe 語法重寫上面的 function 。 我最初的嘗試滿足了基本要求:
summarise_filtered_dplyrish <-
function(df,
subset_arg,
summary_fun,
select_col) {
df %>%
filter({{subset_arg}}) %>%
summarise(across(.cols = {{select_col}}, .fns = summary_fun)) %>%
pull({{select_col}})
}
調用時:
summarise_filtered_dplyrish(mtcars, am == 1, min, cyl)
# [1] 4
我想讓 function 使用:
summarise_filtered_dplyrish(mtcars, "am == 1", "min", "cyl")
語法,除了已經工作的解決方案。 這個怎么做? 到目前為止,上面的調用會產生錯誤:
錯誤:
filter()
輸入..1
有問題。 x 輸入..1
必須是邏輯向量,而不是字符。 ℹ 輸入..1
是"am == 1"
。 運行rlang::last_error()
以查看錯誤發生的位置。
min
和cyl
可以通過ensym()
輕松處理,它適用於字符串和符號。 表達式am == 1
需要更多的工作。 讓我們定義一個幫助器 function 來解析一個 object 只有當它是一個字符串時:
str2expr <- function(.x) {if( is.character(.x) ) rlang::parse_expr(.x) else .x}
我們現在可以捕獲提供給subset_arg
的參數,並在它是字符串時對其進行解析:
summarise_filtered_dplyrish <-
function(df,
subset_arg,
summary_fun,
select_col) {
subset_expr <- rlang::enexpr(subset_arg) %>% str2expr()
df %>%
filter( !!subset_expr ) %>%
summarise(across(.cols = {{select_col}}, .fns = !!ensym(summary_fun))) %>%
pull( !!ensym(select_col) )
}
summarise_filtered_dplyrish( mtcars, am == 1, min, cyl ) # Works
summarise_filtered_dplyrish( mtcars, "am == 1", "min", "cyl" ) # Also works
簡要說明: {{x}}
是!!enquo(x)
的簡寫,它捕獲提供給 function 參數的表達式以及應該評估該表達式的上下文。 由於您的上下文由df
有效定義,因此可以將enquo
放寬到enexpr
(捕獲表達式但不捕獲評估上下文)和ensym
(捕獲包含符號名稱的符號或字符串)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.