I have a custom function that takes as input a data frame and then a selection of columns from that data frame, like this:
library(dplyr)
df <- data.frame(x = c(1, 2, 3, 4, 5), y = c(11, 12, 13, 14, 15))
sample_fun <- function(df, x, y) {
df <- df %>%
mutate(z = {{x}} * {{y}})
}
df_out <- sample_fun(df, x, y)
I'd like to make one of the data frame columns optional, and then have the function test for its presence using !if.null()
. If this was an object, rather than a data frame column, I would do this:
sample_fun <- function(df, x, y = NULL) {
if(!is.null(y)) {
df <- df %>%
mutate(z = {{x}} * y)
}
else(df <- df %>%
mutate(z = {{x}}))
}
df_out <- sample_fun(df, x)
df_out2 <- sample_fun(df, x, y)
However, I can't figure out how to check for the presence of the data column. Both if(!is.null(y))
and if(!is.null({{y}}))
return Error: object 'y' not found
. What is the best way to check for the presence of y, when y is a data frame column rather than an independent object?
I have a custom function that takes as input a data frame and then a selection of columns from that data frame, like this:
library(dplyr)
df <- data.frame(x = c(1, 2, 3, 4, 5), y = c(11, 12, 13, 14, 15))
sample_fun <- function(df, x, y) {
df <- df %>%
mutate(z = {{x}} * {{y}})
}
df_out <- sample_fun(df, x, y)
I'd like to make one of the data frame columns optional, and then have the function test for its presence using !if.null()
. If this was an object, rather than a data frame column, I would do this:
sample_fun <- function(df, x, y = NULL) {
if(!is.null(y)) {
df <- df %>%
mutate(z = {{x}} * y)
}
else(df <- df %>%
mutate(z = {{x}}))
}
df_out <- sample_fun(df, x)
df_out2 <- sample_fun(df, x, y)
However, I can't figure out how to check for the presence of the data column. Both if(!is.null(y))
and if(!is.null({{y}}))
return Error: object 'y' not found
. What is the best way to check for the presence of y, when y is a data frame column rather than an independent object?
- I don't have my R environment running ATM, but this post has lots of information about nulls in dataframes and dplyr stackoverflow.com/questions/46133499/… – MikeAinOz Commented 2 days ago
3 Answers
Reset to default 3One option is to check if the y
variable is missing
, instead of using NULL
as a placeholder.
sample_fun <- function(df, x, y) {
if (!missing(y)) {
df <- mutate(df, z = {{x}} * {{y}})
} else {
df <- mutate(df, z = {{x}})
}
return(df)
}
df_out <- sample_fun(df, x)
df_out2 <- sample_fun(df, x, y)
The problem with the code in the question is that is.null
cannot take an unquoted variable. The code there would work if quo_is_null(enquo(y))
is used in place of is.null(y)
. In that case add a library(rlang)
as well.
Alternately give y
a default value of 1.
library(dplyr)
sample_fun <- function(df, x, y = 1) df %>% mutate(z = {{x}} * {{y}})
sample_fun(df, x, y)
## x y z
## 1 1 11 11
## 2 2 12 24
## 3 3 13 39
## 4 4 14 56
## 5 5 15 75
sample_fun(df, x)
## x y z
## 1 1 11 1
## 2 2 12 2
## 3 3 13 3
## 4 4 14 4
## 5 5 15 5
You could generalize this a little.
sample_fun <- \(data, ..., FUN='*') {
ell <- substitute(list(...))[-1]
if (!is.null(ell)) {
stopifnot(all(as.character(ell) %in% names(data)))
expr <- Reduce(\(x, y) call(FUN, x, y), ell)
transform(data, z=eval(expr))
} else data
}
> sample_fun(df, X1)
X1 X2 X3 z
1 1 3 5 1
2 2 4 6 2
> sample_fun(df, X1, X3)
X1 X2 X3 z
1 1 3 5 5
2 2 4 6 12
> sample_fun(df, X1, X2, X999)
Error in sample_fun(df, X1, X2, X999) :
all(as.character(ell) %in% names(df)) is not TRUE
> sample_fun(df)
X1 X2 X3
1 1 3 5
2 2 4 6
> sample_fun(df, X1, X2, FUN='/')
X1 X2 X3 z
1 1 3 5 0.3333333
2 2 4 6 0.5000000
Data:
> dput(df)
structure(list(X1 = 1:2, X2 = 3:4, X3 = 5:6), class = "data.frame", row.names = c(NA,
-2L))