最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

r - Passing an optional data frame column to a custom function - Stack Overflow

programmeradmin1浏览0评论

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?

Share Improve this question asked 2 days ago JakenJaken 4652 silver badges8 bronze badges 1
  • 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
Add a comment  | 

3 Answers 3

Reset to default 3

One 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))
发布评论

评论列表(0)

  1. 暂无评论