Dot evaluation in summarise_at gives values instead of column name

Hi, the code used to work last week, but now it does not anymore. I used the dot as a column name reference in summarise_at, but now it seems that it is returning the values instead of the name.

Here is an example in which I use a self made function in combination with the dot.

library("tidyverse")

fun1 <- function(df, x){
	x <- enquo(x)
	tmp <- mean(df %>% pull(!!x), na.rm = TRUE)
	return(tmp)
}

df <- tibble(
		BM1 = rnorm(40, mean = 3, sd = 1)
	)

# this used to work, but it does not anymore
df %>%
	summarise_at(
		vars(BM1),
		list(~fun1(df, .))
	)

# when I replace the dot with the column name it works:
df %>%
	summarise_at(
		vars(BM1),
		list(~fun1(df, BM1))
	)

can you try with .x instead of .? Does that change anything?

1 Like

When you use scoped verbs, it's better to think of what you get each time function is called as a vector in your dataframe, not name. I'm not sure why it worked in the first place, but it works if you do this:

library("tidyverse")

fun1 <- function(x){
 mean(x, na.rm = TRUE)
}

df <- tibble(
  BM1 = rnorm(40, mean = 3, sd = 1)
)

# this used to work, but it does not anymore
df %>%
  summarise_at(
    vars(BM1),
    list(~fun1(.x))
  )
#> # A tibble: 1 x 1
#>     BM1
#>   <dbl>
#> 1  3.03

Created on 2019-05-23 by the reprex package (v0.3.0)

1 Like

No it does not.

df %>%
	summarise_at(
		vars(BM1),
		list(~fun1(df, .x))
	)

it seems there was a change in dplyr 0.8.1 in the way vars works for you. From the two examples, we see that vars(BM1) will be put in .x but as a its value and not as a name.
That means your fun1 does not need enquo anymore. The issue is with fun1 and how summarise_at handles it.

I don't know where the change comes from exactly and if it is intended as a breaking change or if it is a bug.

with 0.8.0.1

library(dplyr)
#> 
#> Attachement du package : 'dplyr'
#> The following objects are masked from 'package:stats':
#> 
#>     filter, lag
#> The following objects are masked from 'package:base':
#> 
#>     intersect, setdiff, setequal, union
packageVersion("dplyr")
#> [1] '0.8.0.1'
fun1 <- function(df, x){
  x <- enquo(x)
  tmp <- mean(df %>% pull(!!x), na.rm = TRUE)
  return(tmp)
}

df <- tibble(
  BM1 = rnorm(40, mean = 3, sd = 1)
)

# this used to work, but it does not anymore
df %>%
  summarise_at(
    vars(BM1),
    list(~fun1(df, .))
  )
#> # A tibble: 1 x 1
#>     BM1
#>   <dbl>
#> 1  2.95

Created on 2019-05-24 by the reprex package (v0.3.0.9000)

with last version 0.8.1

library(dplyr)
#> 
#> Attachement du package : 'dplyr'
#> The following objects are masked from 'package:stats':
#> 
#>     filter, lag
#> The following objects are masked from 'package:base':
#> 
#>     intersect, setdiff, setequal, union
packageVersion("dplyr")
#> [1] '0.8.1'
fun1 <- function(df, x){
  x <- enquo(x)
  tmp <- mean(df %>% pull(!!x), na.rm = TRUE)
  return(tmp)
}

df <- tibble(
  BM1 = rnorm(40, mean = 3, sd = 1)
)

# this used to work, but it does not anymore
df %>%
  summarise_at(
    vars(BM1),
    list(~fun1(df, .))
  )
#> `var` must evaluate to a single number or a column name, not a double
#> vector

Created on 2019-05-24 by the reprex package (v0.3.0.9000)

from the error message we understand that something change.
From the example in ?summarise_at, we see that the current behavior is the expected one

library(dplyr)
starwars %>%
    summarise_at(vars(height:mass), mean, na.rm = TRUE)

There is no need for a special fun that knows how to enquo. It just passes the variable from vars as vector and not column name or symbol. Just provide a .funs that know how to handle a column vector. I believe it was a bug in 0.8.0.1 and now works correctly in last version.

4 Likes

Hi, with the latest dplyr package (0.8.1) it is still working as expacted using the soft deprecated funs() function.

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

fun1 <- function(df, x){
    x <- enquo(x)
    tmp <- mean(df %>% pull(!!x), na.rm = TRUE)
    return(tmp)
}

df <- tibble(
        BM1 = rnorm(40, mean = 3, sd = 1)
    )

df %>%
  summarise_at(
  vars(BM1),
    funs(fun1(df, .))
  )
#> Warning: funs() is soft deprecated as of dplyr 0.8.0
#> please use list() instead
#> 
#>   # Before:
#>   funs(name = f(.))
#> 
#>   # After: 
#>   list(name = ~ f(.))
#> This warning is displayed once per session.
#> # A tibble: 1 x 1
#>     BM1
#>   <dbl>
#> 1  2.89

Created on 2019-05-29 by the reprex package (v0.3.0)

There are more examples from Romain in this issue, including how to make it work with list:

2 Likes

This topic was automatically closed 21 days after the last reply. New replies are no longer allowed.