1
votes

I have this data frame

library(tidyverse)
df <- structure(list(D1_step1 = c("FT", "FF", "FF", "TTT", "FFF", "FFF", 
      "FF", "FFF", "FT", "TT"), barrido = c("B1_B4", "B1_B2", "B1_B4", 
      "B1_B2_B4", "B1_B2_B4", "B1_B2_B4", "B1_B4", "B1_B2_B4", "B1_B4", 
      "B1_B4")), class = c("tbl_df", "tbl", "data.frame"), row.names = c(NA, 
      -10L))

AND this function

f1 <- function(sero, barrido){
  as.logical(case_when(str_detect(barrido, "B1") ~ str_sub(sero, 1, 1)))
}

df %>%
mutate(new_col = f1(D1_step1, barrido))

I do this and it works fine. I don't need the barrido argument in the function as this does not vary and the the data always has a column named 'barrido'. Thus I'd like to do this....

f2 <- function(sero){
  as.logical(case_when(str_detect(barrido, "B1") ~ str_sub(sero, 1, 1)))
}

df %>%
mutate(new_col = f2(D1_step1))

 Error in stri_detect_regex(string, pattern, negate = negate, opts_regex = opts(pattern)) : 
  object 'barrido' not found

but computer says no so I tried setting the argument as a default and I got a different kind of no. Nb just edited this as I hadn't actually set the argument as default originally

f3 <- function(sero, barrido = barrido){
  as.logical(case_when(str_detect(barrido, "B1") ~ str_sub(sero, 1, 1)))
}

df %>%
mutate(new_col = f3(D1_step1))

 Error in stri_detect_regex(string, pattern, negate = negate, opts_regex = opts(pattern)) : 
  promise already under evaluation: recursive default argument reference or earlier problems?

Writing a custom case_when function to use in dplyr mutate using tidyeval. This question doesn't help as I don't want to write the function as a case_when within a mutate. The comments below give an indication as to why this not working and lead me to believe that there may be a solution using tidyeval. Also I am curious as to what is behind the difference between the error messages between f2 and f3.

1
Functions are independent, they are not "attached" to your dataframe. So you can also use f1(1:10, 11:20) without any error. (I know it doesn't make sense but just for demonstrating). Also sero and barrido are just variables, you can replace them with a and b in f1 and it will still work. So when you are using barrido in the function it's definition should be present somewhere in the function itself (or in global environment).Ronak Shah
So you want the function to always use the values of barrido in the dataframe where it's being called? There are ways to do this, e.g. you could write the function to accept a dataframe as input rather than individual vectors, but I'm not sure it would be any cleaner than just passing the values of barrido.Marius
@RonakShah. But when I call the function I am using dplyr::mutate which uses NSE so I thought that the dataframe and its variables including 'barrido' are available in the environment of the function call. Maybe I'm wrong.hammoire
@Marius yes. I don't want the function to accept a data frame (i.e. wrap a mutate around it) as it makes naming the new variables hardhammoire
No, as I said functions are independent. They don't know from where they are called. For example for sum function. It works with sum(mtcars$mpg) and also sum(1:10). The functions which you have defined are the same.Ronak Shah

1 Answers

1
votes

With the development version of dplyr (to be released as dplyr 1.0) you can peek at the current columns with across().

f2 <- function(sero){
  barrido <- across(all_of("barrido"))[[1]]
  as.logical(case_when(
    str_detect(barrido, "B1") ~ str_sub(sero, 1, 1)
  ))
}

It should be clearly documented that this function only works inside dplyr with data frames containing a barrido column.