【问题标题】:Using a function in dplyr filter在 dplyr 过滤器中使用函数
【发布时间】:2021-11-30 21:29:24
【问题描述】:

我想定义一个辅助函数来帮助我更清楚地组合一些布尔过滤器。

这是使用iris 数据集的结果的工作示例

library(tidyverse)


sepal_config = function(length, width, species, .data) {
  .data$Sepal.Length > length & .data$Sepal.Width < width & .data$Species == species
}

iris %>% 
  filter(
      sepal_config(length = 4, width = 3, species = "versicolor", .data = .data) |  # 34 rows
      sepal_config(length = 3, width = 3, species = "virginica",  .data = .data)    # 21 rows
    )                                                                               # 55 rows

我想这样做而不必传入.data,并且理想情况下还要在数据框范围内评估列名(即避免此错误)

sepal_config = function(length, width, species) {
  Sepal.Length > length & Sepal.Width < width & Species == species
}

iris %>% 
  filter(
      sepal_config(length = 4, width = 3, species = "versicolor") |
      sepal_config(length = 3, width = 3, species = "virginica")
    )                                                               
Error: Problem with `filter()` input `..1`.
ℹ Input `..1` is `|...`.
x object 'Sepal.Length' not found

不幸的是,我对 NSE 的了解不够深入,无法知道这是否是一种选择。我尝试了programming with dplyr 操作指南中的各种技术,但脚注让我觉得我找错地方了。

dplyr 的 filter() 的灵感来自 base R 的 subset()subset() 提供数据屏蔽,但不提供整洁的评估,因此本章描述的技术不适用于它。

谢谢, 阿基尔

【问题讨论】:

  • 所有dplyr函数filtersummarisemutategroup_by都有数据作为第一个参数。为什么要避免这种情况?如果您希望避免它,您希望如何从数据中获取 Sepal.Length 等值。或者你只是想避免重复调用.data$

标签: r dplyr filter


【解决方案1】:

您可以使用quo() 将表达式包装在您的函数中,并使用!! 运算符在filter() 调用中将其化解。

library(dplyr)

sepal_config = function(length, width, species) {
  quo(Sepal.Length > length & Sepal.Width < width & Species == species)
  }

iris %>% 
  filter(!!sepal_config(length = 4, width = 3, species = "versicolor") |
         !!sepal_config(length = 3, width = 3, species = "virginica"))


   Sepal.Length Sepal.Width Petal.Length Petal.Width    Species
1           5.5         2.3          4.0         1.3 versicolor
2           6.5         2.8          4.6         1.5 versicolor
3           5.7         2.8          4.5         1.3 versicolor
4           4.9         2.4          3.3         1.0 versicolor
5           6.6         2.9          4.6         1.3 versicolor
6           5.2         2.7          3.9         1.4 versicolor
7           5.0         2.0          3.5         1.0 versicolor
8           6.0         2.2          4.0         1.0 versicolor
9           6.1         2.9          4.7         1.4 versicolor
10          5.6         2.9          3.6         1.3 versicolor
...

【讨论】:

  • 这是我一直在寻找的 NSE 魔法。谢谢你:)
【解决方案2】:

dplyr 为这类事情提供了一个函数cur_data()

library(dplyr, warn.conflicts = FALSE)

sepal_config <- function(data, length, width, species, .data = cur_data()) {
  .data$Sepal.Length > length & .data$Sepal.Width < width & .data$Species == species
}

iris %>% 
  as_tibble() %>% 
  filter(
    sepal_config(length = 4, width = 3, species = "versicolor") |  # 34 rows
      sepal_config(length = 3, width = 3, species = "virginica")    # 21 rows
  )     
#> # A tibble: 55 x 5
#>    Sepal.Length Sepal.Width Petal.Length Petal.Width Species   
#>           <dbl>       <dbl>        <dbl>       <dbl> <fct>     
#>  1          5.5         2.3          4           1.3 versicolor
#>  2          6.5         2.8          4.6         1.5 versicolor
#>  3          5.7         2.8          4.5         1.3 versicolor
#>  4          4.9         2.4          3.3         1   versicolor
#>  5          6.6         2.9          4.6         1.3 versicolor
#>  6          5.2         2.7          3.9         1.4 versicolor
#>  7          5           2            3.5         1   versicolor
#>  8          6           2.2          4           1   versicolor
#>  9          6.1         2.9          4.7         1.4 versicolor
#> 10          5.6         2.9          3.6         1.3 versicolor
#> # ... with 45 more rows

reprex package (v2.0.0) 于 2021-10-12 创建

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-30
    • 1970-01-01
    • 2020-03-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多