How to feed a list of unquoted column names into `lapply` (so that I can use it with a `dplyr` function)

前端 未结 3 1809
陌清茗
陌清茗 2021-02-08 14:33

I am trying to write a function in tidyverse/dplyr that I want to eventually use with lapply (or map). (I had been working on it to answer

3条回答
  •  星月不相逢
    2021-02-08 15:03

    Let me first point out that in your initial report function, you can use quo_name to convert the quosure into a string, which you can then use in mutate like the following:

    library(dplyr)
    library(rlang)
    
    report <- function(report_cat){
      report_cat <- enquo(report_cat)
    
      sample_data %>%
        group_by(!!report_cat, YEAR) %>%
        summarize(num=n(),total=sum(AMOUNT)) %>%
        rename(REPORT_VALUE = !!report_cat) %>%
        mutate(REPORT_CATEGORY = quo_name(report_cat))
    }
    
    report(REPORT_CODE)
    

    Now, to address your question of "how to feed a list of unquoted strings through lapply or map to make it work inside dplyr functions", I propose two ways of doing it.

    1. Use rlang::sym to parse your strings and unquote it when feeding into lapply or map

    library(purrr)
    
    cat.list <- c("REPORT_CODE","PAYMENT_METHOD","INBOUND_CHANNEL","AMOUNT_CAT")
    
    map_df(cat.list, ~report(!!sym(.)))    
    

    or with syms you can parse all elements of a vector at once:

    map_df(syms(cat.list), ~report(!!.))
    

    Result:

    # A tibble: 27 x 5
    # Groups:   REPORT_VALUE [16]
       REPORT_VALUE  YEAR   num total REPORT_CATEGORY
                            
     1            J  FY14     1    25     REPORT_CODE
     2            Q  FY16     1     1     REPORT_CODE
     3            Q  FY17     1   100     REPORT_CODE
     4            R  FY17     1    50     REPORT_CODE
     5            R  FY18     2    75     REPORT_CODE
     6            S  FY17     2   400     REPORT_CODE
     7            S  FY18     2   530     REPORT_CODE
     8        Check  FY14     1    25  PAYMENT_METHOD
     9        Check  FY17     1    50  PAYMENT_METHOD
    10        Check  FY18     2    55  PAYMENT_METHOD
    # ... with 17 more rows 
    

    2. Rewrite your report function by placing lapply or map inside so that report can do NSE

    report <- function(...){
      report_cat <- quos(...)
    
      map_df(report_cat, function(x) sample_data %>%
                 group_by(!!x, YEAR) %>%
                 summarize(num=n(),total=sum(AMOUNT)) %>%
                 rename(REPORT_VALUE = !!x) %>%
                 mutate(REPORT_CATEGORY = quo_name(x)))
    }
    

    By placing map_df inside report, you can take advantage of quos, which converts ... to list of quosures. They are then fed into map_df and unquoted one by one using !!.

    report(REPORT_CODE, PAYMENT_METHOD, INBOUND_CHANNEL, AMOUNT_CAT)
    

    Another advantage of writing it like this is that you can also supply a vector of string symbols and splice them using !!! like the following:

    report(!!!syms(cat.list))
    

    Result:

    # A tibble: 27 x 5
    # Groups:   REPORT_VALUE [16]
       REPORT_VALUE  YEAR   num total REPORT_CATEGORY
                            
     1            J  FY14     1    25     REPORT_CODE
     2            Q  FY16     1     1     REPORT_CODE
     3            Q  FY17     1   100     REPORT_CODE
     4            R  FY17     1    50     REPORT_CODE
     5            R  FY18     2    75     REPORT_CODE
     6            S  FY17     2   400     REPORT_CODE
     7            S  FY18     2   530     REPORT_CODE
     8        Check  FY14     1    25  PAYMENT_METHOD
     9        Check  FY17     1    50  PAYMENT_METHOD
    10        Check  FY18     2    55  PAYMENT_METHOD
    # ... with 17 more rows
    

提交回复
热议问题