【问题标题】:Use a variable name as function argument使用变量名作为函数参数
【发布时间】:2022-01-28 10:48:14
【问题描述】:

我想编写一个独特的函数来(除其他外)为不同阈值的不同变量过滤数据库。我找到了一种在函数本身中指示我想要过滤的变量的方法,但不确定是最好的方法。

我应该怎么做?

example_db <- data.frame(name=c("A","B","C"), 
                         value_1=c(1,2,3), 
                         value_2=c(2,3,1))

advanced_filter <- function(data,variable,limit){
  
  require(dplyr)
  data <- data %>% 
    dplyr::filter(variabe>limit) 
  
  return(data)
}

预期结果:

advanced_filter(example_db,value_1,2)

name value_1 value_2
1    C       3       1

我的尝试:

advance_filter <- function(data,variable,limit){
  require(dplyr)
  f <- paste(variable, ">",  limit)
  data <- data %>% 
    dplyr::filter_(f) 
  
  return(data)
}


advance_filter(example_db,"value_1",2)

【问题讨论】:

    标签: r variables dplyr filter tidyverse


    【解决方案1】:

    也许你让这变得比它需要的更复杂:

    advanced_filter <- function(data, variable, limit) {
      data[data[variable] > limit,]
    }
    
    advanced_filter(example_db, "value_1", 2)
    #>   name value_1 value_2
    #> 3    C       3       1
    

    reprex package (v2.0.1) 于 2022-01-28 创建

    【讨论】:

    • +1 鼓励人们考虑在基础 R 中简单地做事,而非常常见的下意识反应是在 dplyr 中做所有事情,即使这更复杂。
    【解决方案2】:

    Allan Cameron 的回答显然是正确的,只需要 base R,只是为了后代的缘故,这里是整洁的版本。

    example_db <- data.frame(name=c("A","B","C"), 
                             value_1=c(1,2,3), 
                             value_2=c(2,3,1))
    
    
    
    advanced_filter <- function(data,variable,limit){
      require(dplyr)
      vbl <- enquo(variable)
      data %>% 
        dplyr::filter(!!vbl > limit) 
    }
    
    advanced_filter(example_db,value_1,2)
    #> Loading required package: dplyr
    #> 
    #> Attaching package: 'dplyr'
    #> The following objects are masked from 'package:stats':
    #> 
    #>     filter, lag
    #> The following objects are masked from 'package:base':
    #> 
    #>     intersect, setdiff, setequal, union
    #>   name value_1 value_2
    #> 1    C       3       1
    

    reprex package (v2.0.1) 于 2022-01-28 创建

    或者,在下面@TimTeaFan 的评论之后:

    example_db <- data.frame(name=c("A","B","C"), 
                             value_1=c(1,2,3), 
                             value_2=c(2,3,1))
    
    
    
    advanced_filter <- function(data,variable,limit){
      require(dplyr)
      data %>% 
        dplyr::filter({{variable}} > limit) 
    }
    
    advanced_filter(example_db,value_1,2)
    #> Loading required package: dplyr
    #> 
    #> Attaching package: 'dplyr'
    #> The following objects are masked from 'package:stats':
    #> 
    #>     filter, lag
    #> The following objects are masked from 'package:base':
    #> 
    #>     intersect, setdiff, setequal, union
    #>   name value_1 value_2
    #> 1    C       3       1
    

    reprex package (v2.0.1) 于 2022-01-28 创建

    【讨论】:

    • 也许您还可以使用{{ }} 提及变量隧道。那么我们就不需要enquodata %&gt;% dplyr::filter({{ variable }} &gt; limit)
    • 谢谢@TimTeaFan。我将其添加到答案中。还查看了您的 {dplyover} 包 - 很高兴尝试一下。
    【解决方案3】:

    如果您希望能够将向量名称用作字符串,可以是完全限定的 - 或仅用作符号,您可以使用以下 Base R 解决方案:

    # Function:
    advanced_filter <- function(data, variable, limit) {
      if(is.character(substitute(variable))){
        variable_str <- variable
      }else{
        variable_str <- gsub(".*\\$", "", deparse(substitute(variable)))
      }
      res <- data[data[,variable_str] > limit,]
      return(res)
    }
    # Application:
    advanced_filter(example_db, "value_1", 2)
    advanced_filter(example_db, value_1, 2)
    advanced_filter(example_db, example_db$value_1, 2)
    

    【讨论】:

      猜你喜欢
      • 2014-12-28
      • 1970-01-01
      • 1970-01-01
      • 2013-09-20
      • 1970-01-01
      • 2021-12-17
      • 2012-01-14
      相关资源
      最近更新 更多