r语言 - 如果参数在 dplyr 中不为空,则使用函数参数有条件地添加管道



我有一个带有参数subset的函数,其默认值为NULL。在函数中,如果subsetNULL我不想添加条件管道。否则,我想在管道中使用subset的值:

library(tidyverse)
f <- function(subset = NULL){

iris %>% 
{if (is.null(substitute(subset))) . else filter(., {{ subset }} < 2.2)}

}
f() # gives error posted below
## Desired output: entire iris dataset
f(subset = Sepal.Width) # works
Sepal.Length Sepal.Width Petal.Length Petal.Width    Species
1            5           2          3.5           1 versicolor

但是,使用大括号,{{ subset}}subset = NULL时评估得太早,并试图过滤NULL < 2.2的位置。f()返回以下错误:

错误:输入..1filter()问题。

x 输入..1的大小必须为 150 或 1,而不是大小为 0。

i 输入..1NULL < 2.2

您应该在函数体中计算is.null(substitute(subset)),而不是在if子句中计算。该子句的计算方式(由于堆栈管理%>%)与父子句的计算方式不同。

这有效:

f <- function(subset = NULL){
isnull <- is.null(substitute(subset))
iris %>% 
{if (isnull) . else filter(., {{ subset }} < 2.2)}
}
head( f() )
#   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
# 1          5.1         3.5          1.4         0.2  setosa
# 2          4.9         3.0          1.4         0.2  setosa
# 3          4.7         3.2          1.3         0.2  setosa
# 4          4.6         3.1          1.5         0.2  setosa
# 5          5.0         3.6          1.4         0.2  setosa
# 6          5.4         3.9          1.7         0.4  setosa
f(subset = Sepal.Width)
#   Sepal.Length Sepal.Width Petal.Length Petal.Width    Species
# 1            5           2          3.5           1 versicolor

这是一种在发生error时返回完整数据集的方法tryCatch

f <- function(subset = NULL){
tryCatch(  iris %>% 
filter({{ subset }} < 2.2)
, error = function(err) iris)

}

-测试

dim(f())
#[1] 150   5
dim(f(subset = Sepal.Width))
#[1] 1 5

我发现了一种可能不是最优雅的方法,但它的优点是相当清晰和直观。

首先,我将对象转换为字符串,并与数据集中的变量进行比较。如果您输入的对象不存在,它将按原样返回数据。如果该列依次在数据集中,它将使用 bang-bang 运算符对其进行过滤,!!结合使用sym将您的字符串转换为符号。

希望这对你有用。

library(dplyr)
f <- function(data, subset = NULL, value = 2.2) {
subsetName = deparse(substitute(subset))
if (!subsetName %in% names(data)) {return(data)}
return(data %>% filter(!!sym(subsetName) < value))
}

最新更新