【问题标题】:Conditionally add pipe using function argument if argument is not null with dplyr如果 dplyr 的参数不为空,则使用函数参数有条件地添加管道
【发布时间】:2021-04-20 16:43:01
【问题描述】:

我有一个带有参数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 &lt; 2.2 的位置。 f() 返回以下错误:

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

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

我输入..1NULL &lt; 2.2

【问题讨论】:

    标签: r dplyr


    【解决方案1】:

    您应该在函数体中评估is.null(substitute(subset)),而不是在if 子句中。该子句的评估方式不同于父子句(由于%&gt;% 堆栈管理)。

    这行得通:

    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
    

    【讨论】:

    • (在发布之前我没有看到 akrun 的回答,不知道为什么,但这解决了你的第二个表达式。)
    【解决方案2】:

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

    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
    

    【讨论】:

    • +1 用于使用 python 的“请求宽恕”方法,不幸的是,R 对tryCatch(., error=) 的性能不如 python 对try: . except: 的性能好(不幸的是,它在 R 中明显慢得多)。
    【解决方案3】:

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

    首先,我将对象转换为字符串并与数据集中的变量进行比较。如果您输入的对象不存在,它将按原样返回数据。如果该列又在数据集中,它将使用 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))
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-06
      • 2022-11-29
      • 1970-01-01
      • 2015-12-22
      • 2021-09-30
      相关资源
      最近更新 更多