簡體   English   中英

dplyr'ish 方法來簡單子集/總結 function

[英]dplyr'ish approach to simple subset/summarise function

背景

提供的 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()以查看錯誤發生的位置。

mincyl可以通過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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM