Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to adjust to different behavior of across .fn argument passing in dplyr 1.1.1 vs. 1.0.10? #6809

Open
eipi10 opened this issue Mar 27, 2023 · 14 comments

Comments

@eipi10
Copy link
Contributor

eipi10 commented Mar 27, 2023

I have a summarizing function that's similar to the function below. It allows the user to pass grouping variables, summary variables and any number of summary functions as arguments.

# Allow user to choose summary function(s)
fnc = function(data, summary.vars=NULL, group.vars=NULL, 
               FUNS=c(mean=~mean(., na.rm=TRUE))) {
  data %>% 
    group_by(across({{group.vars}})) %>% 
    summarise(n=n(), across({{summary.vars}}, 
                            .fn=FUNS,
                            .names="{.col}_{.fn}"))
}

I often use weighted.mean as a summary function in the FUNS argument, which requires a weighting variable, which I pass with the bare column name, like this:

mtcars %>% fnc(c(mpg, hp), c(vs, am), 
               FUNS=c(mean=~mean(., na.rm=TRUE), 
                      mean.wted=~weighted.mean(., w=cyl, na.rm=TRUE)))

This approach worked in dplyr 1.0.10 and previous versions, but is failing in dplyr 1.1.1. Reproducible examples are below, first with 1.0.10 then with 1.1.1.

How can I update my function so that it will work properly with dplyr 1.1.1? I've never been happy with hard-coding the w argument anyway. Is there some tidyeval way that I should be passing the w argument into the summary function?

Example with dplyr 1.0.10

library(dplyr)
#> 
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#> 
#>     filter, lag
#> The following objects are masked from 'package:base':
#> 
#>     intersect, setdiff, setequal, union

# Allow user to choose summary function(s)
fnc = function(data, summary.vars=NULL, group.vars=NULL, 
               FUNS=c(mean=~mean(., na.rm=TRUE))) {
  data %>% 
    group_by(across({{group.vars}})) %>% 
    summarise(n=n(), across({{summary.vars}}, 
                            .fn=FUNS,
                            .names="{.col}_{.fn}"))
}

# These work in both 1.0.10 and 1.1.1
mtcars %>% fnc(c(mpg, hp))
#> # A tibble: 1 × 3
#>       n mpg_mean hp_mean
#>   <int>    <dbl>   <dbl>
#> 1    32     20.1    147.

mtcars %>% fnc(c(mpg, hp), c(vs, am))
#> `summarise()` has grouped output by 'vs'. You can override using the `.groups`
#> argument.
#> # A tibble: 4 × 5
#> # Groups:   vs [2]
#>      vs    am     n mpg_mean hp_mean
#>   <dbl> <dbl> <int>    <dbl>   <dbl>
#> 1     0     0    12     15.0   194. 
#> 2     0     1     6     19.8   181. 
#> 3     1     0     7     20.7   102. 
#> 4     1     1     7     28.4    80.6

# Passing a weighting variable as the w argument in weighted.mean works in dplyr 1.0.10 but fails in dplyr 1.1.1
mtcars %>% fnc(c(mpg, hp), c(vs, am), 
               FUNS=c(mean=~mean(., na.rm=TRUE), 
                      mean.wted=~weighted.mean(., w=cyl, na.rm=TRUE)))
#> `summarise()` has grouped output by 'vs'. You can override using the `.groups`
#> argument.
#> # A tibble: 4 × 7
#> # Groups:   vs [2]
#>      vs    am     n mpg_mean mpg_mean.wted hp_mean hp_mean.wted
#>   <dbl> <dbl> <int>    <dbl>         <dbl>   <dbl>        <dbl>
#> 1     0     0    12     15.0          15.1   194.         194. 
#> 2     0     1     6     19.8          19.0   181.         198. 
#> 3     1     0     7     20.7          20.4   102.         105. 
#> 4     1     1     7     28.4          28.4    80.6         80.6

sessionInfo()
#> R version 4.2.2 (2022-10-31)
#> Platform: aarch64-apple-darwin20 (64-bit)
#> Running under: macOS Ventura 13.2.1
#> 
#> Matrix products: default
#> BLAS:   /Library/Frameworks/R.framework/Versions/4.2-arm64/Resources/lib/libRblas.0.dylib
#> LAPACK: /Library/Frameworks/R.framework/Versions/4.2-arm64/Resources/lib/libRlapack.dylib
#> 
#> locale:
#> [1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
#> 
#> attached base packages:
#> [1] stats     graphics  grDevices utils     datasets  methods   base     
#> 
#> other attached packages:
#> [1] dplyr_1.0.10
#> 
#> loaded via a namespace (and not attached):
#>  [1] rstudioapi_0.14   knitr_1.42        magrittr_2.0.3    tidyselect_1.2.0 
#>  [5] R.cache_0.16.0    R6_2.5.1          rlang_1.1.0.9000  fastmap_1.1.1    
#>  [9] fansi_1.0.4       styler_1.9.1      tools_4.2.2       xfun_0.37        
#> [13] R.oo_1.25.0       utf8_1.2.3        DBI_1.1.3         cli_3.6.1        
#> [17] withr_2.5.0       htmltools_0.5.4   yaml_2.3.7        digest_0.6.31    
#> [21] tibble_3.2.1      lifecycle_1.0.3   purrr_1.0.1       vctrs_0.6.0.9000 
#> [25] R.utils_2.12.2    fs_1.6.1          glue_1.6.2        evaluate_0.20    
#> [29] rmarkdown_2.20    reprex_2.0.2      compiler_4.2.2    pillar_1.8.1     
#> [33] generics_0.1.3    R.methodsS3_1.8.2 pkgconfig_2.0.3

Same example, but with dplyr 1.1.1

library(dplyr)
#> 
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#> 
#>     filter, lag
#> The following objects are masked from 'package:base':
#> 
#>     intersect, setdiff, setequal, union

# Allow user to choose summary function(s)
fnc = function(data, summary.vars=NULL, group.vars=NULL, 
               FUNS=c(mean=~mean(., na.rm=TRUE))) {
  data %>% 
    group_by(across({{group.vars}})) %>% 
    summarise(n=n(), across({{summary.vars}}, 
                            .fn=FUNS,
                            .names="{.col}_{.fn}"))
}

# These work in both 1.0.10 and 1.1.1
mtcars %>% fnc(c(mpg, hp))
#> # A tibble: 1 × 3
#>       n mpg_mean hp_mean
#>   <int>    <dbl>   <dbl>
#> 1    32     20.1    147.

mtcars %>% fnc(c(mpg, hp), c(vs, am))
#> `summarise()` has grouped output by 'vs'. You can override using the `.groups`
#> argument.
#> # A tibble: 4 × 5
#> # Groups:   vs [2]
#>      vs    am     n mpg_mean hp_mean
#>   <dbl> <dbl> <int>    <dbl>   <dbl>
#> 1     0     0    12     15.0   194. 
#> 2     0     1     6     19.8   181. 
#> 3     1     0     7     20.7   102. 
#> 4     1     1     7     28.4    80.6

# Passing a weighting variable as the w argument in weighted.mean works in dplyr 1.0.10 but fails in dplyr 1.1.1
mtcars %>% fnc(c(mpg, hp), c(vs, am), 
               FUNS=c(mean=~mean(., na.rm=TRUE), 
                      mean.wted=~weighted.mean(., w=cyl, na.rm=TRUE)))
#> Error in `summarise()`:
#> ℹ In argument: `across(c(mpg, hp), .fn = FUNS, .names =
#>   "{.col}_{.fn}")`.
#> ℹ In group 1: `vs = 0`, `am = 0`.
#> Caused by error in `across()`:
#> ! Can't compute column `mpg_mean.wted`.
#> Caused by error in `weighted.mean.default()`:
#> ! object 'cyl' not found
#> Backtrace:
#>      ▆
#>   1. ├─mtcars %>% ...
#>   2. ├─global fnc(...)
#>   3. │ └─data %>% group_by(across({{ group.vars }})) %>% ...
#>   4. ├─dplyr::summarise(...)
#>   5. ├─dplyr:::summarise.grouped_df(...)
#>   6. │ └─dplyr:::summarise_cols(.data, dplyr_quosures(...), by, "summarise")
#>   7. │   ├─base::withCallingHandlers(...)
#>   8. │   └─dplyr:::map(quosures, summarise_eval_one, mask = mask)
#>   9. │     └─base::lapply(.x, .f, ...)
#>  10. │       └─dplyr (local) FUN(X[[i]], ...)
#>  11. │         ├─base::withCallingHandlers(...)
#>  12. │         └─mask$eval_all_summarise(quo)
#>  13. │           └─dplyr (local) eval()
#>  14. ├─`<rlng_lm_>`(mpg)
#>  15. │ ├─stats::weighted.mean(., w = cyl, na.rm = TRUE)
#>  16. │ └─stats:::weighted.mean.default(., w = cyl, na.rm = TRUE)
#>  17. └─base::.handleSimpleError(...)
#>  18.   └─dplyr (local) h(simpleError(msg, call))
#>  19.     └─rlang::abort(msg, call = call("across"), parent = cnd)

sessionInfo()
#> R version 4.2.2 (2022-10-31)
#> Platform: aarch64-apple-darwin20 (64-bit)
#> Running under: macOS Ventura 13.2.1
#> 
#> Matrix products: default
#> BLAS:   /Library/Frameworks/R.framework/Versions/4.2-arm64/Resources/lib/libRblas.0.dylib
#> LAPACK: /Library/Frameworks/R.framework/Versions/4.2-arm64/Resources/lib/libRlapack.dylib
#> 
#> locale:
#> [1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
#> 
#> attached base packages:
#> [1] stats     graphics  grDevices utils     datasets  methods   base     
#> 
#> other attached packages:
#> [1] dplyr_1.1.1
#> 
#> loaded via a namespace (and not attached):
#>  [1] rstudioapi_0.14   knitr_1.42        magrittr_2.0.3    tidyselect_1.2.0 
#>  [5] R.cache_0.16.0    R6_2.5.1          rlang_1.1.0.9000  fastmap_1.1.1    
#>  [9] fansi_1.0.4       styler_1.9.1      tools_4.2.2       xfun_0.37        
#> [13] R.oo_1.25.0       utf8_1.2.3        cli_3.6.0         withr_2.5.0      
#> [17] htmltools_0.5.4   yaml_2.3.7        digest_0.6.31     tibble_3.2.1     
#> [21] lifecycle_1.0.3   purrr_1.0.1       vctrs_0.6.0.9000  R.utils_2.12.2   
#> [25] fs_1.6.1          glue_1.6.2        evaluate_0.20     rmarkdown_2.20   
#> [29] reprex_2.0.2      compiler_4.2.2    pillar_1.8.1      generics_0.1.3   
#> [33] R.methodsS3_1.8.2 pkgconfig_2.0.3
@eipi10 eipi10 changed the title How to adjust to different behavior of weighted.mean in dplyr 1.1.1 vs. 1.0.10? How to adjust to different behavior of function argument passing in dplyr 1.1.1 vs. 1.0.10? Mar 27, 2023
@eipi10 eipi10 changed the title How to adjust to different behavior of function argument passing in dplyr 1.1.1 vs. 1.0.10? How to adjust to different behavior of .fns argument passing in dplyr 1.1.1 vs. 1.0.10? Mar 27, 2023
@eipi10 eipi10 changed the title How to adjust to different behavior of .fns argument passing in dplyr 1.1.1 vs. 1.0.10? How to adjust to different behavior of .fn argument passing in dplyr 1.1.1 vs. 1.0.10? Mar 27, 2023
@eipi10 eipi10 changed the title How to adjust to different behavior of .fn argument passing in dplyr 1.1.1 vs. 1.0.10? How to adjust to different behavior of across .fn argument passing in dplyr 1.1.1 vs. 1.0.10? Mar 27, 2023
@DavisVaughan
Copy link
Member

Minimal reprex

1.0.10:

# pak::pak("tidyverse/[email protected]")
library(dplyr, warn.conflicts = FALSE)

df <- tibble(x = 1:5, w = 2:6)

fn <- function(data, cols, fns) {
  summarise(data, across(.cols = {{cols}}, .fns = fns))
}

# Works from top level
summarise(df, across(x, ~weighted.mean(.x, w = w)))
#> # A tibble: 1 × 1
#>       x
#>   <dbl>
#> 1   3.5

# Works when wrapped
fn(df, x, ~weighted.mean(.x, w = w))
#> # A tibble: 1 × 1
#>       x
#>   <dbl>
#> 1   3.5

1.1.1:

library(dplyr, warn.conflicts = FALSE)

df <- tibble(x = 1:5, w = 2:6)

fn <- function(data, cols, fns) {
  summarise(data, across(.cols = {{cols}}, .fns = fns))
}

# Works from top level
summarise(df, across(x, ~weighted.mean(.x, w = w)))
#> # A tibble: 1 × 1
#>       x
#>   <dbl>
#> 1   3.5

# Not when wrapped
fn(df, x, ~weighted.mean(.x, w = w))
#> Error in `summarise()`:
#> ℹ In argument: `across(.cols = x, .fns = fns)`.
#> Caused by error in `across()`:
#> ! Can't compute column `x`.
#> Caused by error in `weighted.mean.default()`:
#> ! object 'w' not found

@DavisVaughan
Copy link
Member

DavisVaughan commented Mar 31, 2023

Possible solution proposed by @lionel- is to allow .fns = {{ fns }} so that users can wrap with a pattern like:

fn <- function(data, cols, fns) {
  summarise(data, across(.cols = {{cols}}, .fns = {{fns}}))
}

The justification here being that if across() is a true templating function then it needs to be able to access the original expressions for .fns, so they need to come through with {{

@eipi10
Copy link
Contributor Author

eipi10 commented Mar 31, 2023

Actually, that already works (assuming I'm understanding what you and @lionel- had in mind):

library(tidyverse)

fn <- function(data, cols, fns, groups=NULL) {
  data %>% 
    group_by(across({{groups}})) %>% 
    summarise(across(.cols = {{cols}}, .fns = {{fns}}))
}

d = tibble(
  x1=1:5, x2=11:15, w=2:6, g=rep(LETTERS[1:2], c(2,3))
) 

fn(d, 
   cols=c(x1,x2), 
   fns=c(mean=mean, mean.wt=~weighted.mean(., w=w)), 
   groups=g)
#> # A tibble: 2 × 5
#>   g     x1_mean x1_mean.wt x2_mean x2_mean.wt
#>   <chr>   <dbl>      <dbl>   <dbl>      <dbl>
#> 1 A         1.5       1.6     11.5       11.6
#> 2 B         4         4.13    14         14.1

fn(mtcars, 
   cols=c(mpg, hp), 
   fns=c(mean=mean, mean.wt=~weighted.mean(., w=cyl)), 
   groups=c(am, vs))
#> `summarise()` has grouped output by 'am'. You can override using the `.groups`
#> argument.
#> # A tibble: 4 × 6
#> # Groups:   am [2]
#>      am    vs mpg_mean mpg_mean.wt hp_mean hp_mean.wt
#>   <dbl> <dbl>    <dbl>       <dbl>   <dbl>      <dbl>
#> 1     0     0     15.0        15.1   194.       194. 
#> 2     0     1     20.7        20.4   102.       105. 
#> 3     1     0     19.8        19.0   181.       198. 
#> 4     1     1     28.4        28.4    80.6       80.6

Created on 2023-03-31 with reprex v2.0.2

Session info
sessioninfo::session_info()
#> ─ Session info ───────────────────────────────────────────────────────────────
#>  setting  value
#>  version  R version 4.2.2 (2022-10-31)
#>  os       macOS Ventura 13.2.1
#>  system   aarch64, darwin20
#>  ui       X11
#>  language (EN)
#>  collate  en_US.UTF-8
#>  ctype    en_US.UTF-8
#>  tz       America/Los_Angeles
#>  date     2023-03-31
#>  pandoc   2.19.2 @ /Applications/RStudio.app/Contents/Resources/app/quarto/bin/tools/ (via rmarkdown)
#> 
#> ─ Packages ───────────────────────────────────────────────────────────────────
#>  package     * version    date (UTC) lib source
#>  cli           3.6.1      2023-03-23 [1] CRAN (R 4.2.0)
#>  colorspace    2.1-0      2023-01-23 [1] CRAN (R 4.2.0)
#>  digest        0.6.31     2022-12-11 [1] CRAN (R 4.2.0)
#>  dplyr       * 1.1.1      2023-03-22 [1] CRAN (R 4.2.0)
#>  evaluate      0.20       2023-01-17 [1] CRAN (R 4.2.0)
#>  fansi         1.0.4      2023-01-22 [1] CRAN (R 4.2.0)
#>  fastmap       1.1.1      2023-02-24 [1] CRAN (R 4.2.0)
#>  forcats     * 1.0.0      2023-01-29 [1] CRAN (R 4.2.0)
#>  fs            1.6.1      2023-02-06 [1] CRAN (R 4.2.0)
#>  generics      0.1.3      2022-07-05 [1] CRAN (R 4.2.0)
#>  ggplot2     * 3.4.1      2023-02-10 [1] CRAN (R 4.2.0)
#>  glue          1.6.2      2022-02-24 [1] CRAN (R 4.2.0)
#>  gtable        0.3.3      2023-03-21 [1] CRAN (R 4.2.0)
#>  hms           1.1.3      2023-03-21 [1] CRAN (R 4.2.0)
#>  htmltools     0.5.5      2023-03-23 [1] CRAN (R 4.2.0)
#>  knitr         1.42       2023-01-25 [1] CRAN (R 4.2.0)
#>  lifecycle     1.0.3      2022-10-07 [1] CRAN (R 4.2.0)
#>  lubridate   * 1.9.2      2023-02-10 [1] CRAN (R 4.2.0)
#>  magrittr      2.0.3      2022-03-30 [1] CRAN (R 4.2.0)
#>  munsell       0.5.0      2018-06-12 [1] CRAN (R 4.2.0)
#>  pillar        1.9.0      2023-03-22 [1] CRAN (R 4.2.0)
#>  pkgconfig     2.0.3      2019-09-22 [1] CRAN (R 4.2.0)
#>  purrr       * 1.0.1      2023-01-10 [1] CRAN (R 4.2.0)
#>  R.cache       0.16.0     2022-07-21 [1] CRAN (R 4.2.0)
#>  R.methodsS3   1.8.2      2022-06-13 [1] CRAN (R 4.2.0)
#>  R.oo          1.25.0     2022-06-12 [1] CRAN (R 4.2.0)
#>  R.utils       2.12.2     2022-11-11 [1] CRAN (R 4.2.0)
#>  R6            2.5.1      2021-08-19 [1] CRAN (R 4.2.0)
#>  readr       * 2.1.4      2023-02-10 [1] CRAN (R 4.2.0)
#>  reprex        2.0.2      2022-08-17 [1] CRAN (R 4.2.0)
#>  rlang         1.1.0.9000 2023-03-21 [1] Github (r-lib/rlang@ea2fe5f)
#>  rmarkdown     2.21       2023-03-26 [1] CRAN (R 4.2.2)
#>  rstudioapi    0.14       2022-08-22 [1] CRAN (R 4.2.0)
#>  scales        1.2.1      2022-08-20 [1] CRAN (R 4.2.0)
#>  sessioninfo   1.2.2      2021-12-06 [1] CRAN (R 4.2.0)
#>  stringi       1.7.12     2023-01-11 [1] CRAN (R 4.2.0)
#>  stringr     * 1.5.0      2022-12-02 [1] CRAN (R 4.2.0)
#>  styler        1.9.1      2023-03-04 [1] CRAN (R 4.2.0)
#>  tibble      * 3.2.1      2023-03-20 [1] CRAN (R 4.2.0)
#>  tidyr       * 1.3.0      2023-01-24 [1] CRAN (R 4.2.0)
#>  tidyselect    1.2.0      2022-10-10 [1] CRAN (R 4.2.0)
#>  tidyverse   * 2.0.0      2023-02-22 [1] CRAN (R 4.2.0)
#>  timechange    0.2.0      2023-01-11 [1] CRAN (R 4.2.2)
#>  tzdb          0.3.0      2022-03-28 [1] CRAN (R 4.2.0)
#>  utf8          1.2.3      2023-01-31 [1] CRAN (R 4.2.0)
#>  vctrs         0.6.1      2023-03-22 [1] CRAN (R 4.2.0)
#>  withr         2.5.0      2022-03-03 [1] CRAN (R 4.2.0)
#>  xfun          0.38       2023-03-24 [1] CRAN (R 4.2.0)
#>  yaml          2.3.7      2023-01-23 [1] CRAN (R 4.2.0)
#> 
#>  [1] /Users/***/Library/R/arm64/4.2/library
#>  [2] /Library/Frameworks/R.framework/Versions/4.2-arm64/Resources/library
#> 
#> ──────────────────────────────────────────────────────────────────────────────

@eipi10
Copy link
Contributor Author

eipi10 commented Apr 1, 2023

Oh, but it doesn't work if you pass a separate object as the fns argument:

library(tidyverse)

fn <- function(data, cols, fns, groups=NULL) {
  data %>% 
    group_by(across({{groups}})) %>% 
    summarise(across(.cols = {{cols}}, .fns = {{fns}}))
}

fn(mtcars, 
   cols=c(mpg, hp), 
   fns=c(mean=mean, mean.wt=~weighted.mean(., w=cyl)),
   groups=c(am, vs))
#> `summarise()` has grouped output by 'am'. You can override using the `.groups`
#> argument.
#> # A tibble: 4 × 6
#> # Groups:   am [2]
#>      am    vs mpg_mean mpg_mean.wt hp_mean hp_mean.wt
#>   <dbl> <dbl>    <dbl>       <dbl>   <dbl>      <dbl>
#> 1     0     0     15.0        15.1   194.       194. 
#> 2     0     1     20.7        20.4   102.       105. 
#> 3     1     0     19.8        19.0   181.       198. 
#> 4     1     1     28.4        28.4    80.6       80.6

FUNS = c(mean=mean, mean.wt=~weighted.mean(., w=cyl))

fn(mtcars, 
   cols=c(mpg, hp), 
   fns=FUNS, 
   groups=c(am, vs))
#> Error in `summarise()`:
#> ℹ In argument: `across(.cols = c(mpg, hp), .fns = FUNS)`.
#> ℹ In group 1: `am = 0`, `vs = 0`.
#> Caused by error in `across()`:
#> ! Can't compute column `mpg_mean.wt`.
#> Caused by error in `weighted.mean.default()`:
#> ! object 'cyl' not found
#> Backtrace:
#>      ▆
#>   1. ├─global fn(mtcars, cols = c(mpg, hp), fns = FUNS, groups = c(am, vs))
#>   2. │ └─data %>% group_by(across({{ groups }})) %>% ...
#>   3. ├─dplyr::summarise(...)
#>   4. ├─dplyr:::summarise.grouped_df(...)
#>   5. │ └─dplyr:::summarise_cols(.data, dplyr_quosures(...), by, "summarise")
#>   6. │   ├─base::withCallingHandlers(...)
#>   7. │   └─dplyr:::map(quosures, summarise_eval_one, mask = mask)
#>   8. │     └─base::lapply(.x, .f, ...)
#>   9. │       └─dplyr (local) FUN(X[[i]], ...)
#>  10. │         ├─base::withCallingHandlers(...)
#>  11. │         └─mask$eval_all_summarise(quo)
#>  12. │           └─dplyr (local) eval()
#>  13. ├─global `<rlng_lm_>`(mpg)
#>  14. │ ├─stats::weighted.mean(., w = cyl)
#>  15. │ └─stats:::weighted.mean.default(., w = cyl)
#>  16. └─base::.handleSimpleError(...)
#>  17.   └─dplyr (local) h(simpleError(msg, call))
#>  18.     └─rlang::abort(msg, call = call("across"), parent = cnd)

Created on 2023-04-01 with reprex v2.0.2

Session info
sessioninfo::session_info()
#> ─ Session info ───────────────────────────────────────────────────────────────
#>  setting  value
#>  version  R version 4.2.2 (2022-10-31)
#>  os       macOS Ventura 13.2.1
#>  system   aarch64, darwin20
#>  ui       X11
#>  language (EN)
#>  collate  en_US.UTF-8
#>  ctype    en_US.UTF-8
#>  tz       America/Los_Angeles
#>  date     2023-04-01
#>  pandoc   2.19.2 @ /Applications/RStudio.app/Contents/Resources/app/quarto/bin/tools/ (via rmarkdown)
#> 
#> ─ Packages ───────────────────────────────────────────────────────────────────
#>  package     * version    date (UTC) lib source
#>  cli           3.6.1      2023-03-23 [1] CRAN (R 4.2.0)
#>  colorspace    2.1-0      2023-01-23 [1] CRAN (R 4.2.0)
#>  digest        0.6.31     2022-12-11 [1] CRAN (R 4.2.0)
#>  dplyr       * 1.1.1      2023-03-22 [1] CRAN (R 4.2.0)
#>  evaluate      0.20       2023-01-17 [1] CRAN (R 4.2.0)
#>  fansi         1.0.4      2023-01-22 [1] CRAN (R 4.2.0)
#>  fastmap       1.1.1      2023-02-24 [1] CRAN (R 4.2.0)
#>  forcats     * 1.0.0      2023-01-29 [1] CRAN (R 4.2.0)
#>  fs            1.6.1      2023-02-06 [1] CRAN (R 4.2.0)
#>  generics      0.1.3      2022-07-05 [1] CRAN (R 4.2.0)
#>  ggplot2     * 3.4.1      2023-02-10 [1] CRAN (R 4.2.0)
#>  glue          1.6.2      2022-02-24 [1] CRAN (R 4.2.0)
#>  gtable        0.3.3      2023-03-21 [1] CRAN (R 4.2.0)
#>  hms           1.1.3      2023-03-21 [1] CRAN (R 4.2.0)
#>  htmltools     0.5.5      2023-03-23 [1] CRAN (R 4.2.0)
#>  knitr         1.42       2023-01-25 [1] CRAN (R 4.2.0)
#>  lifecycle     1.0.3      2022-10-07 [1] CRAN (R 4.2.0)
#>  lubridate   * 1.9.2      2023-02-10 [1] CRAN (R 4.2.0)
#>  magrittr      2.0.3      2022-03-30 [1] CRAN (R 4.2.0)
#>  munsell       0.5.0      2018-06-12 [1] CRAN (R 4.2.0)
#>  pillar        1.9.0      2023-03-22 [1] CRAN (R 4.2.0)
#>  pkgconfig     2.0.3      2019-09-22 [1] CRAN (R 4.2.0)
#>  purrr       * 1.0.1      2023-01-10 [1] CRAN (R 4.2.0)
#>  R.cache       0.16.0     2022-07-21 [1] CRAN (R 4.2.0)
#>  R.methodsS3   1.8.2      2022-06-13 [1] CRAN (R 4.2.0)
#>  R.oo          1.25.0     2022-06-12 [1] CRAN (R 4.2.0)
#>  R.utils       2.12.2     2022-11-11 [1] CRAN (R 4.2.0)
#>  R6            2.5.1      2021-08-19 [1] CRAN (R 4.2.0)
#>  readr       * 2.1.4      2023-02-10 [1] CRAN (R 4.2.0)
#>  reprex        2.0.2      2022-08-17 [1] CRAN (R 4.2.0)
#>  rlang         1.1.0.9000 2023-03-21 [1] Github (r-lib/rlang@ea2fe5f)
#>  rmarkdown     2.21       2023-03-26 [1] CRAN (R 4.2.2)
#>  rstudioapi    0.14       2022-08-22 [1] CRAN (R 4.2.0)
#>  scales        1.2.1      2022-08-20 [1] CRAN (R 4.2.0)
#>  sessioninfo   1.2.2      2021-12-06 [1] CRAN (R 4.2.0)
#>  stringi       1.7.12     2023-01-11 [1] CRAN (R 4.2.0)
#>  stringr     * 1.5.0      2022-12-02 [1] CRAN (R 4.2.0)
#>  styler        1.9.1      2023-03-04 [1] CRAN (R 4.2.0)
#>  tibble      * 3.2.1      2023-03-20 [1] CRAN (R 4.2.0)
#>  tidyr       * 1.3.0      2023-01-24 [1] CRAN (R 4.2.0)
#>  tidyselect    1.2.0      2022-10-10 [1] CRAN (R 4.2.0)
#>  tidyverse   * 2.0.0      2023-02-22 [1] CRAN (R 4.2.0)
#>  timechange    0.2.0      2023-01-11 [1] CRAN (R 4.2.2)
#>  tzdb          0.3.0      2022-03-28 [1] CRAN (R 4.2.0)
#>  utf8          1.2.3      2023-01-31 [1] CRAN (R 4.2.0)
#>  vctrs         0.6.1      2023-03-22 [1] CRAN (R 4.2.0)
#>  withr         2.5.0      2022-03-03 [1] CRAN (R 4.2.0)
#>  xfun          0.38       2023-03-24 [1] CRAN (R 4.2.0)
#>  yaml          2.3.7      2023-01-23 [1] CRAN (R 4.2.0)
#> 
#>  [1] /Users/jschwartz/Library/R/arm64/4.2/library
#>  [2] /Library/Frameworks/R.framework/Versions/4.2-arm64/Resources/library
#> 
#> ──────────────────────────────────────────────────────────────────────────────

@DavisVaughan
Copy link
Member

That probably can't and won't ever work because we can't "see" the expression that built the original object, we only see FUNS

@eipi10
Copy link
Contributor Author

eipi10 commented Apr 2, 2023

As a result of my incomplete understanding of how NSE might interact with different ways of passing arguments, I failed to include a separate FUNS object as an example in my initial post.

I just want to point out that in dplyr 1.0.10 you can pass a separate FUNS object into a summary function, without using embrasure, and the summary function works, even when you pass additional columns inside one or more of the functions within FUNS, such as the w argument in weighted.mean. But this approach fails in dplyr 1.1.1. Because I do this often, I ran into this problem almost immediately after I installed 1.1.1. Below are reproducible examples with 1.0.10 and 1.1.1.

You can pass the .fns argument explicitly if you use embrasure, as in my post above, but how can I make the FUNS example below work in 1.1.1 as it does in 1.0.10 (preferably in a way that also works with an explicit .fns argument)?

dplyr 1.0.10: Passing an (unembraced) .fns (directly or as an object) works

library(tidyverse)

fn <- function(data, cols, fns, groups=NULL) {
  data %>% 
    group_by(across({{groups}})) %>% 
    summarise(across(.cols = {{cols}}, .fns = fns))
}

fn(mtcars, 
   cols=c(mpg, hp), 
   fns=c(mean=mean, mean.wt=~weighted.mean(., w=cyl)),
   groups=c(am, vs))
#> `summarise()` has grouped output by 'am'. You can override using the `.groups`
#> argument.
#> # A tibble: 4 × 6
#> # Groups:   am [2]
#>      am    vs mpg_mean mpg_mean.wt hp_mean hp_mean.wt
#>   <dbl> <dbl>    <dbl>       <dbl>   <dbl>      <dbl>
#> 1     0     0     15.0        15.1   194.       194. 
#> 2     0     1     20.7        20.4   102.       105. 
#> 3     1     0     19.8        19.0   181.       198. 
#> 4     1     1     28.4        28.4    80.6       80.6

FUNS = c(mean=mean, mean.wt=~weighted.mean(., w=cyl))

fn(mtcars, 
   cols=c(mpg, hp), 
   fns=FUNS, 
   groups=c(am, vs))
#> `summarise()` has grouped output by 'am'. You can override using the `.groups`
#> argument.
#> # A tibble: 4 × 6
#> # Groups:   am [2]
#>      am    vs mpg_mean mpg_mean.wt hp_mean hp_mean.wt
#>   <dbl> <dbl>    <dbl>       <dbl>   <dbl>      <dbl>
#> 1     0     0     15.0        15.1   194.       194. 
#> 2     0     1     20.7        20.4   102.       105. 
#> 3     1     0     19.8        19.0   181.       198. 
#> 4     1     1     28.4        28.4    80.6       80.6

Created on 2023-04-01 with reprex v2.0.2

Session info
sessioninfo::session_info()
#> ─ Session info ───────────────────────────────────────────────────────────────
#>  setting  value
#>  version  R version 4.2.2 (2022-10-31)
#>  os       macOS Ventura 13.2.1
#>  system   aarch64, darwin20
#>  ui       X11
#>  language (EN)
#>  collate  en_US.UTF-8
#>  ctype    en_US.UTF-8
#>  tz       America/Los_Angeles
#>  date     2023-04-01
#>  pandoc   2.19.2 @ /Applications/RStudio.app/Contents/Resources/app/quarto/bin/tools/ (via rmarkdown)
#> 
#> ─ Packages ───────────────────────────────────────────────────────────────────
#>  package     * version    date (UTC) lib source
#>  cli           3.6.1      2023-03-23 [1] CRAN (R 4.2.0)
#>  colorspace    2.1-0      2023-01-23 [1] CRAN (R 4.2.0)
#>  DBI           1.1.3      2022-06-18 [1] CRAN (R 4.2.0)
#>  digest        0.6.31     2022-12-11 [1] CRAN (R 4.2.0)
#>  dplyr       * 1.0.10     2022-09-01 [1] CRAN (R 4.2.2)
#>  evaluate      0.20       2023-01-17 [1] CRAN (R 4.2.0)
#>  fansi         1.0.4      2023-01-22 [1] CRAN (R 4.2.0)
#>  fastmap       1.1.1      2023-02-24 [1] CRAN (R 4.2.0)
#>  forcats     * 1.0.0      2023-01-29 [1] CRAN (R 4.2.0)
#>  fs            1.6.1      2023-02-06 [1] CRAN (R 4.2.0)
#>  generics      0.1.3      2022-07-05 [1] CRAN (R 4.2.0)
#>  ggplot2     * 3.4.1      2023-02-10 [1] CRAN (R 4.2.0)
#>  glue          1.6.2      2022-02-24 [1] CRAN (R 4.2.0)
#>  gtable        0.3.3      2023-03-21 [1] CRAN (R 4.2.0)
#>  hms           1.1.3      2023-03-21 [1] CRAN (R 4.2.0)
#>  htmltools     0.5.5      2023-03-23 [1] CRAN (R 4.2.0)
#>  knitr         1.42       2023-01-25 [1] CRAN (R 4.2.0)
#>  lifecycle     1.0.3      2022-10-07 [1] CRAN (R 4.2.0)
#>  lubridate   * 1.9.2      2023-02-10 [1] CRAN (R 4.2.0)
#>  magrittr      2.0.3      2022-03-30 [1] CRAN (R 4.2.0)
#>  munsell       0.5.0      2018-06-12 [1] CRAN (R 4.2.0)
#>  pillar        1.9.0      2023-03-22 [1] CRAN (R 4.2.0)
#>  pkgconfig     2.0.3      2019-09-22 [1] CRAN (R 4.2.0)
#>  purrr       * 1.0.1      2023-01-10 [1] CRAN (R 4.2.0)
#>  R.cache       0.16.0     2022-07-21 [1] CRAN (R 4.2.0)
#>  R.methodsS3   1.8.2      2022-06-13 [1] CRAN (R 4.2.0)
#>  R.oo          1.25.0     2022-06-12 [1] CRAN (R 4.2.0)
#>  R.utils       2.12.2     2022-11-11 [1] CRAN (R 4.2.0)
#>  R6            2.5.1      2021-08-19 [1] CRAN (R 4.2.0)
#>  readr       * 2.1.4      2023-02-10 [1] CRAN (R 4.2.0)
#>  reprex        2.0.2      2022-08-17 [1] CRAN (R 4.2.0)
#>  rlang         1.1.0.9000 2023-03-21 [1] Github (r-lib/rlang@ea2fe5f)
#>  rmarkdown     2.21       2023-03-26 [1] CRAN (R 4.2.2)
#>  rstudioapi    0.14       2022-08-22 [1] CRAN (R 4.2.0)
#>  scales        1.2.1      2022-08-20 [1] CRAN (R 4.2.0)
#>  sessioninfo   1.2.2      2021-12-06 [1] CRAN (R 4.2.0)
#>  stringi       1.7.12     2023-01-11 [1] CRAN (R 4.2.0)
#>  stringr     * 1.5.0      2022-12-02 [1] CRAN (R 4.2.0)
#>  styler        1.9.1      2023-03-04 [1] CRAN (R 4.2.0)
#>  tibble      * 3.2.1      2023-03-20 [1] CRAN (R 4.2.0)
#>  tidyr       * 1.3.0      2023-01-24 [1] CRAN (R 4.2.0)
#>  tidyselect    1.2.0      2022-10-10 [1] CRAN (R 4.2.0)
#>  tidyverse   * 2.0.0      2023-02-22 [1] CRAN (R 4.2.0)
#>  timechange    0.2.0      2023-01-11 [1] CRAN (R 4.2.2)
#>  tzdb          0.3.0      2022-03-28 [1] CRAN (R 4.2.0)
#>  utf8          1.2.3      2023-01-31 [1] CRAN (R 4.2.0)
#>  vctrs         0.6.1      2023-03-22 [1] CRAN (R 4.2.0)
#>  withr         2.5.0      2022-03-03 [1] CRAN (R 4.2.0)
#>  xfun          0.38       2023-03-24 [1] CRAN (R 4.2.0)
#>  yaml          2.3.7      2023-01-23 [1] CRAN (R 4.2.0)
#> 
#>  [1] /Users/jschwartz/Library/R/arm64/4.2/library
#>  [2] /Library/Frameworks/R.framework/Versions/4.2-arm64/Resources/library
#> 
#> ──────────────────────────────────────────────────────────────────────────────

dplyr 1.1.1: Passing an (unembraced) .fns (directly or as an object) fails

library(tidyverse)

fn <- function(data, cols, fns, groups=NULL) {
  data %>% 
    group_by(across({{groups}})) %>% 
    summarise(across(.cols = {{cols}}, .fns = fns))
}

fn(mtcars, 
   cols=c(mpg, hp), 
   fns=c(mean=mean, mean.wt=~weighted.mean(., w=cyl)),
   groups=c(am, vs))
#> Error in `summarise()`:
#> ℹ In argument: `across(.cols = c(mpg, hp), .fns = fns)`.
#> ℹ In group 1: `am = 0`, `vs = 0`.
#> Caused by error in `across()`:
#> ! Can't compute column `mpg_mean.wt`.
#> Caused by error in `weighted.mean.default()`:
#> ! object 'cyl' not found
#> Backtrace:
#>      ▆
#>   1. ├─global fn(...)
#>   2. │ └─data %>% group_by(across({{ groups }})) %>% ...
#>   3. ├─dplyr::summarise(...)
#>   4. ├─dplyr:::summarise.grouped_df(...)
#>   5. │ └─dplyr:::summarise_cols(.data, dplyr_quosures(...), by, "summarise")
#>   6. │   ├─base::withCallingHandlers(...)
#>   7. │   └─dplyr:::map(quosures, summarise_eval_one, mask = mask)
#>   8. │     └─base::lapply(.x, .f, ...)
#>   9. │       └─dplyr (local) FUN(X[[i]], ...)
#>  10. │         ├─base::withCallingHandlers(...)
#>  11. │         └─mask$eval_all_summarise(quo)
#>  12. │           └─dplyr (local) eval()
#>  13. ├─global `<rlng_lm_>`(mpg)
#>  14. │ ├─stats::weighted.mean(., w = cyl)
#>  15. │ └─stats:::weighted.mean.default(., w = cyl)
#>  16. └─base::.handleSimpleError(...)
#>  17.   └─dplyr (local) h(simpleError(msg, call))
#>  18.     └─rlang::abort(msg, call = call("across"), parent = cnd)

FUNS = c(mean=mean, mean.wt=~weighted.mean(., w=cyl))

fn(mtcars, 
   cols=c(mpg, hp), 
   fns=FUNS, 
   groups=c(am, vs))
#> Error in `summarise()`:
#> ℹ In argument: `across(.cols = c(mpg, hp), .fns = fns)`.
#> ℹ In group 1: `am = 0`, `vs = 0`.
#> Caused by error in `across()`:
#> ! Can't compute column `mpg_mean.wt`.
#> Caused by error in `weighted.mean.default()`:
#> ! object 'cyl' not found
#> Backtrace:
#>      ▆
#>   1. ├─global fn(mtcars, cols = c(mpg, hp), fns = FUNS, groups = c(am, vs))
#>   2. │ └─data %>% group_by(across({{ groups }})) %>% ...
#>   3. ├─dplyr::summarise(...)
#>   4. ├─dplyr:::summarise.grouped_df(...)
#>   5. │ └─dplyr:::summarise_cols(.data, dplyr_quosures(...), by, "summarise")
#>   6. │   ├─base::withCallingHandlers(...)
#>   7. │   └─dplyr:::map(quosures, summarise_eval_one, mask = mask)
#>   8. │     └─base::lapply(.x, .f, ...)
#>   9. │       └─dplyr (local) FUN(X[[i]], ...)
#>  10. │         ├─base::withCallingHandlers(...)
#>  11. │         └─mask$eval_all_summarise(quo)
#>  12. │           └─dplyr (local) eval()
#>  13. ├─global `<rlng_lm_>`(mpg)
#>  14. │ ├─stats::weighted.mean(., w = cyl)
#>  15. │ └─stats:::weighted.mean.default(., w = cyl)
#>  16. └─base::.handleSimpleError(...)
#>  17.   └─dplyr (local) h(simpleError(msg, call))
#>  18.     └─rlang::abort(msg, call = call("across"), parent = cnd)

Created on 2023-04-01 with reprex v2.0.2

Session info
sessioninfo::session_info()
#> ─ Session info ───────────────────────────────────────────────────────────────
#>  setting  value
#>  version  R version 4.2.2 (2022-10-31)
#>  os       macOS Ventura 13.2.1
#>  system   aarch64, darwin20
#>  ui       X11
#>  language (EN)
#>  collate  en_US.UTF-8
#>  ctype    en_US.UTF-8
#>  tz       America/Los_Angeles
#>  date     2023-04-01
#>  pandoc   2.19.2 @ /Applications/RStudio.app/Contents/Resources/app/quarto/bin/tools/ (via rmarkdown)
#> 
#> ─ Packages ───────────────────────────────────────────────────────────────────
#>  package     * version    date (UTC) lib source
#>  cli           3.6.1      2023-03-23 [1] CRAN (R 4.2.0)
#>  colorspace    2.1-0      2023-01-23 [1] CRAN (R 4.2.0)
#>  digest        0.6.31     2022-12-11 [1] CRAN (R 4.2.0)
#>  dplyr       * 1.1.1      2023-03-22 [1] CRAN (R 4.2.2)
#>  evaluate      0.20       2023-01-17 [1] CRAN (R 4.2.0)
#>  fansi         1.0.4      2023-01-22 [1] CRAN (R 4.2.0)
#>  fastmap       1.1.1      2023-02-24 [1] CRAN (R 4.2.0)
#>  forcats     * 1.0.0      2023-01-29 [1] CRAN (R 4.2.0)
#>  fs            1.6.1      2023-02-06 [1] CRAN (R 4.2.0)
#>  generics      0.1.3      2022-07-05 [1] CRAN (R 4.2.0)
#>  ggplot2     * 3.4.1      2023-02-10 [1] CRAN (R 4.2.0)
#>  glue          1.6.2      2022-02-24 [1] CRAN (R 4.2.0)
#>  gtable        0.3.3      2023-03-21 [1] CRAN (R 4.2.0)
#>  hms           1.1.3      2023-03-21 [1] CRAN (R 4.2.0)
#>  htmltools     0.5.5      2023-03-23 [1] CRAN (R 4.2.0)
#>  knitr         1.42       2023-01-25 [1] CRAN (R 4.2.0)
#>  lifecycle     1.0.3      2022-10-07 [1] CRAN (R 4.2.0)
#>  lubridate   * 1.9.2      2023-02-10 [1] CRAN (R 4.2.0)
#>  magrittr      2.0.3      2022-03-30 [1] CRAN (R 4.2.0)
#>  munsell       0.5.0      2018-06-12 [1] CRAN (R 4.2.0)
#>  pillar        1.9.0      2023-03-22 [1] CRAN (R 4.2.0)
#>  pkgconfig     2.0.3      2019-09-22 [1] CRAN (R 4.2.0)
#>  purrr       * 1.0.1      2023-01-10 [1] CRAN (R 4.2.0)
#>  R.cache       0.16.0     2022-07-21 [1] CRAN (R 4.2.0)
#>  R.methodsS3   1.8.2      2022-06-13 [1] CRAN (R 4.2.0)
#>  R.oo          1.25.0     2022-06-12 [1] CRAN (R 4.2.0)
#>  R.utils       2.12.2     2022-11-11 [1] CRAN (R 4.2.0)
#>  R6            2.5.1      2021-08-19 [1] CRAN (R 4.2.0)
#>  readr       * 2.1.4      2023-02-10 [1] CRAN (R 4.2.0)
#>  reprex        2.0.2      2022-08-17 [1] CRAN (R 4.2.0)
#>  rlang         1.1.0.9000 2023-03-21 [1] Github (r-lib/rlang@ea2fe5f)
#>  rmarkdown     2.21       2023-03-26 [1] CRAN (R 4.2.2)
#>  rstudioapi    0.14       2022-08-22 [1] CRAN (R 4.2.0)
#>  scales        1.2.1      2022-08-20 [1] CRAN (R 4.2.0)
#>  sessioninfo   1.2.2      2021-12-06 [1] CRAN (R 4.2.0)
#>  stringi       1.7.12     2023-01-11 [1] CRAN (R 4.2.0)
#>  stringr     * 1.5.0      2022-12-02 [1] CRAN (R 4.2.0)
#>  styler        1.9.1      2023-03-04 [1] CRAN (R 4.2.0)
#>  tibble      * 3.2.1      2023-03-20 [1] CRAN (R 4.2.0)
#>  tidyr       * 1.3.0      2023-01-24 [1] CRAN (R 4.2.0)
#>  tidyselect    1.2.0      2022-10-10 [1] CRAN (R 4.2.0)
#>  tidyverse   * 2.0.0      2023-02-22 [1] CRAN (R 4.2.0)
#>  timechange    0.2.0      2023-01-11 [1] CRAN (R 4.2.2)
#>  tzdb          0.3.0      2022-03-28 [1] CRAN (R 4.2.0)
#>  utf8          1.2.3      2023-01-31 [1] CRAN (R 4.2.0)
#>  vctrs         0.6.1      2023-03-22 [1] CRAN (R 4.2.0)
#>  withr         2.5.0      2022-03-03 [1] CRAN (R 4.2.0)
#>  xfun          0.38       2023-03-24 [1] CRAN (R 4.2.0)
#>  yaml          2.3.7      2023-01-23 [1] CRAN (R 4.2.0)
#> 
#>  [1] /Users/jschwartz/Library/R/arm64/4.2/library
#>  [2] /Library/Frameworks/R.framework/Versions/4.2-arm64/Resources/library
#> 
#> ──────────────────────────────────────────────────────────────────────────────

@randy3k
Copy link

randy3k commented Apr 6, 2023

I believe that the new behavior was introduced in #6550
IMO, the new behavior is better, it removes ambiguities. For example, in the above example,

fn <- function(data, cols, fns, groups=NULL) {
  data %>% 
    group_by(across({{groups}})) %>% 
    summarise(across(.cols = {{cols}}, .fns = fns))
}

fn(mtcars, 
   cols=c(mpg, hp), 
   fns=c(mean=mean, mean.wt=~weighted.mean(., w=cyl)),
   groups=c(am, vs))

It is unclear if cyl should be from the data frame or a global variable.

@lionel-
Copy link
Member

lionel- commented Apr 6, 2023

I would expect cyl to be picked up from the data frame in that example, consistently with dplyr semantics. This can be achieved by interpolating .fns with .fns = {{ .fns }}. We'll test and document this as an official pattern.

@eipi10
Copy link
Contributor Author

eipi10 commented Apr 6, 2023

@lionel- the code below fails in dplyr 1.1.1 even though it uses embracing operator, so I think I'm not understanding your previous comment. Is there a different pattern I should be using to pass FUNS into a summarizing function in a way that will work with weighted.mean (or other functions that similarly require ancillary columns to be passed into the .fns argument)?

library(tidyverse)

fn <- function(data, cols, fns, groups=NULL) {
  data %>% 
    group_by(across({{groups}})) %>% 
    summarise(across(.cols = {{cols}}, .fns = {{fns}}))
}

FUNS = c(mean=mean, mean.wt=~weighted.mean(., w=cyl))

fn(mtcars, 
   cols=c(mpg, hp), 
   fns=FUNS, 
   groups=c(am, vs))
#> Error in `summarise()`:
#> ℹ In argument: `across(.cols = c(mpg, hp), .fns = FUNS)`.
#> ℹ In group 1: `am = 0`, `vs = 0`.
#> Caused by error in `across()`:
#> ! Can't compute column `mpg_mean.wt`.
#> Caused by error in `weighted.mean.default()`:
#> ! object 'cyl' not found
#> Backtrace:
#>      ▆
#>   1. ├─global fn(mtcars, cols = c(mpg, hp), fns = FUNS, groups = c(am, vs))
#>   2. │ └─data %>% group_by(across({{ groups }})) %>% ...
#>   3. ├─dplyr::summarise(...)
#>   4. ├─dplyr:::summarise.grouped_df(...)
#>   5. │ └─dplyr:::summarise_cols(.data, dplyr_quosures(...), by, "summarise")
#>   6. │   ├─base::withCallingHandlers(...)
#>   7. │   └─dplyr:::map(quosures, summarise_eval_one, mask = mask)
#>   8. │     └─base::lapply(.x, .f, ...)
#>   9. │       └─dplyr (local) FUN(X[[i]], ...)
#>  10. │         ├─base::withCallingHandlers(...)
#>  11. │         └─mask$eval_all_summarise(quo)
#>  12. │           └─dplyr (local) eval()
#>  13. ├─global `<rlng_lm_>`(mpg)
#>  14. │ ├─stats::weighted.mean(., w = cyl)
#>  15. │ └─stats:::weighted.mean.default(., w = cyl)
#>  16. └─base::.handleSimpleError(...)
#>  17.   └─dplyr (local) h(simpleError(msg, call))
#>  18.     └─rlang::abort(msg, call = call("across"), parent = cnd)

Created on 2023-04-06 with reprex v2.0.2

Session info
sessioninfo::session_info()
#> ─ Session info ───────────────────────────────────────────────────────────────
#>  setting  value
#>  version  R version 4.2.3 (2023-03-15)
#>  os       macOS Ventura 13.2.1
#>  system   aarch64, darwin20
#>  ui       X11
#>  language (EN)
#>  collate  en_US.UTF-8
#>  ctype    en_US.UTF-8
#>  tz       America/Los_Angeles
#>  date     2023-04-06
#>  pandoc   2.19.2 @ /Applications/RStudio.app/Contents/Resources/app/quarto/bin/tools/ (via rmarkdown)
#> 
#> ─ Packages ───────────────────────────────────────────────────────────────────
#>  package     * version    date (UTC) lib source
#>  cli           3.6.1      2023-03-23 [1] CRAN (R 4.2.0)
#>  colorspace    2.1-0      2023-01-23 [1] CRAN (R 4.2.0)
#>  digest        0.6.31     2022-12-11 [1] CRAN (R 4.2.0)
#>  dplyr       * 1.1.1      2023-03-22 [1] CRAN (R 4.2.2)
#>  evaluate      0.20       2023-01-17 [1] CRAN (R 4.2.0)
#>  fansi         1.0.4      2023-01-22 [1] CRAN (R 4.2.0)
#>  fastmap       1.1.1      2023-02-24 [1] CRAN (R 4.2.0)
#>  forcats     * 1.0.0      2023-01-29 [1] CRAN (R 4.2.0)
#>  fs            1.6.1      2023-02-06 [1] CRAN (R 4.2.0)
#>  generics      0.1.3      2022-07-05 [1] CRAN (R 4.2.0)
#>  ggplot2     * 3.4.2      2023-04-03 [1] CRAN (R 4.2.0)
#>  glue          1.6.2      2022-02-24 [1] CRAN (R 4.2.0)
#>  gtable        0.3.3      2023-03-21 [1] CRAN (R 4.2.0)
#>  hms           1.1.3      2023-03-21 [1] CRAN (R 4.2.0)
#>  htmltools     0.5.5      2023-03-23 [1] CRAN (R 4.2.0)
#>  knitr         1.42       2023-01-25 [1] CRAN (R 4.2.0)
#>  lifecycle     1.0.3      2022-10-07 [1] CRAN (R 4.2.0)
#>  lubridate   * 1.9.2      2023-02-10 [1] CRAN (R 4.2.0)
#>  magrittr      2.0.3      2022-03-30 [1] CRAN (R 4.2.0)
#>  munsell       0.5.0      2018-06-12 [1] CRAN (R 4.2.0)
#>  pillar        1.9.0      2023-03-22 [1] CRAN (R 4.2.0)
#>  pkgconfig     2.0.3      2019-09-22 [1] CRAN (R 4.2.0)
#>  purrr       * 1.0.1      2023-01-10 [1] CRAN (R 4.2.0)
#>  R.cache       0.16.0     2022-07-21 [1] CRAN (R 4.2.0)
#>  R.methodsS3   1.8.2      2022-06-13 [1] CRAN (R 4.2.0)
#>  R.oo          1.25.0     2022-06-12 [1] CRAN (R 4.2.0)
#>  R.utils       2.12.2     2022-11-11 [1] CRAN (R 4.2.0)
#>  R6            2.5.1      2021-08-19 [1] CRAN (R 4.2.0)
#>  readr       * 2.1.4      2023-02-10 [1] CRAN (R 4.2.0)
#>  reprex        2.0.2      2022-08-17 [1] CRAN (R 4.2.0)
#>  rlang         1.1.0.9000 2023-03-21 [1] Github (r-lib/rlang@ea2fe5f)
#>  rmarkdown     2.21       2023-03-26 [1] CRAN (R 4.2.2)
#>  rstudioapi    0.14       2022-08-22 [1] CRAN (R 4.2.0)
#>  scales        1.2.1      2022-08-20 [1] CRAN (R 4.2.0)
#>  sessioninfo   1.2.2      2021-12-06 [1] CRAN (R 4.2.0)
#>  stringi       1.7.12     2023-01-11 [1] CRAN (R 4.2.0)
#>  stringr     * 1.5.0      2022-12-02 [1] CRAN (R 4.2.0)
#>  styler        1.9.1      2023-03-04 [1] CRAN (R 4.2.0)
#>  tibble      * 3.2.1      2023-03-20 [1] CRAN (R 4.2.0)
#>  tidyr       * 1.3.0      2023-01-24 [1] CRAN (R 4.2.0)
#>  tidyselect    1.2.0      2022-10-10 [1] CRAN (R 4.2.0)
#>  tidyverse   * 2.0.0      2023-02-22 [1] CRAN (R 4.2.0)
#>  timechange    0.2.0      2023-01-11 [1] CRAN (R 4.2.2)
#>  tzdb          0.3.0      2022-03-28 [1] CRAN (R 4.2.0)
#>  utf8          1.2.3      2023-01-31 [1] CRAN (R 4.2.0)
#>  vctrs         0.6.1      2023-03-22 [1] CRAN (R 4.2.0)
#>  withr         2.5.0      2022-03-03 [1] CRAN (R 4.2.0)
#>  xfun          0.38       2023-03-24 [1] CRAN (R 4.2.0)
#>  yaml          2.3.7      2023-01-23 [1] CRAN (R 4.2.0)
#> 
#>  [1] /Users/jschwartz/Library/R/arm64/4.2/library
#>  [2] /Library/Frameworks/R.framework/Versions/4.2-arm64/Resources/library
#> 
#> ──────────────────────────────────────────────────────────────────────────────

@randy3k
Copy link

randy3k commented Apr 7, 2023

@eipi10
It is still possible, but you need to defuse and inject the expression.

FUNS = quo(c(mean=mean, mean.wt=~weighted.mean(., w=cyl)))

fn(mtcars, 
   cols=c(mpg, hp), 
   fns=!!FUNS, 
   groups=c(am, vs))

@eipi10
Copy link
Contributor Author

eipi10 commented Apr 7, 2023

Thanks @randy3k!

@galenholt
Copy link

I found this after experiencing the identical issue- needing to use weighted.mean with a data-variable for the weights in an across, with weighted.mean being one of many possible user-supplied functions. These functions are typically defined in a list by a user (or programatically), which is then passed to a function essentially the same as fn above, essentially identically to @randy3k 's comment above.

While the solution works, it is causing headaches for users, who have to remember to wrap their list of functions in rlang::quo sometimes and use !! in the call. In addition, if a list of functions is generated programatically, getting that quo wrapper is not straightforward.

I see @randy3k 's point about ambiguities, but I wonder if there's a way to explicitly remove them while avoiding the need to wrap the whole set of functions in quo. A solution that allowed an explict data reference would remove the ambiguity, e.g.
FUNS <- list(mean = mean, mean.wt = ~weighted.mean(., w = .data$cyl). Is that possible?

I've tried to get that to work in a few different ways by using eval_tidy to provide the .data pronoun inside the summary(across)) with no success and maybe it just doesn't work- I get confused quickly trying to understand what is actually happening with the stack and what can be referenced by the time we're inside the summarize(across()).

@olivroy
Copy link

olivroy commented Oct 4, 2023

I used rlang::as_function(). It seemed to work. But I am not too sure of the implications.

@eipi10
Copy link
Contributor Author

eipi10 commented May 31, 2024

Just checking back here to see if there is now (or will eventually be) a better way to pass function arguments within across. By "better," I mean better than having to remember to defuse the function(s) by wrapping in quo and then later inject with !!.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants