17

我正在尝试组合一个函数,该函数从我的原始数据框创建一个子集,然后使用 dplyr 的 SELECT 和 MUTATE 根据萼片/花瓣的宽度和长度之和为我提供大/小条目的数量.

filter <- function (spp, LENGTH, WIDTH) {
  d <- subset (iris, subset=iris$Species == spp) # This part seems to work just fine
  large <- d %>%                       
    select (LENGTH, WIDTH) %>%   # This is where the problem arises.
    mutate (sum = LENGTH + WIDTH) 
  big_samples <- which(large$sum > 4)
 return (length(big_samples)) 
}

基本上,我希望函数返回大花的数量。但是,当我运行该函数时,出现以下错误 -

filter("virginica", "Sepal.Length", "Sepal.Width")

 Error: All select() inputs must resolve to integer column positions.
The following do not:
*  LENGTH
*  WIDTH 

我究竟做错了什么?

4

3 回答 3

21

您遇到了 NSE/SE 问题,请参阅小插图了解更多信息

简而言之,dplyr使用名称的非标准评估 (NSE),并将列的名称传递给函数会破坏它,而不使用标准评估 (SE) 版本。

函数的 SE 版本dplyr以 _ 结尾。您可以看到它select_与您的原始参数很好地配合。

但是,使用函数时事情会变得更加复杂。我们可以使用lazyeval::interp将大多数函数参数转换为列名,请参阅下面的函数中调用的转换mutate以及mutate_更一般的帮助:?lazyeval::interp

尝试:

filter <- function (spp, LENGTH, WIDTH) {
    d <- subset (iris, subset=iris$Species == spp) 
    large <- d %>%                       
        select_(LENGTH, WIDTH) %>%  
        mutate_(sum = lazyeval::interp(~X + Y, X = as.name(LENGTH), Y = as.name(WIDTH))) 
    big_samples <- which(large$sum > 4)
    return (length(big_samples)) 
}
于 2015-12-09T19:12:05.760 回答
12

更新:从 dplyr 0.7.0 开始,您可以使用 tidy eval 来完成此操作。

有关详细信息,请参阅http://dplyr.tidyverse.org/articles/programming.html 。

filter_big <- function(spp, LENGTH, WIDTH) {
  LENGTH <- enquo(LENGTH)                    # Create quosure
  WIDTH  <- enquo(WIDTH)                     # Create quosure

  iris %>% 
    filter(Species == spp) %>% 
    select(!!LENGTH, !!WIDTH) %>%            # Use !! to unquote the quosure
    mutate(sum = (!!LENGTH) + (!!WIDTH)) %>% # Use !! to unquote the quosure
    filter(sum > 4) %>% 
    nrow()
}

filter_big("virginica", Sepal.Length, Sepal.Width)

> filter_big("virginica", Sepal.Length, Sepal.Width)
[1] 50
于 2017-06-23T21:01:58.923 回答
4

如果 quosure 和 quasiquotation 对您来说太多,请使用.data[[ ]]rlang {{ }}( curly curly ) 代替。有关更多信息,请参阅Hadley Wickham 的 5 分钟视频关于整洁评估和(可能)在 Hadley 的 Advanced R 书中的整洁评估部分。

library(rlang)
library(dplyr)

filter_data <- function(df, spp, LENGTH, WIDTH) {
  res <- df %>% 
    filter(Species == spp) %>% 
    select(.data[[LENGTH]], .data[[WIDTH]]) %>%        
    mutate(sum = .data[[LENGTH]] + .data[[WIDTH]]) %>% 
    filter(sum > 4) %>% 
    nrow()
  return(res)
}

filter_data(iris, "virginica", "Sepal.Length", "Sepal.Width")
#> [1] 50


filter_rlang <- function(df, spp, LENGTH, WIDTH) {
  res <- df %>% 
    filter(Species == spp) %>% 
    select({{LENGTH}}, {{WIDTH}}) %>%        
    mutate(sum = {{LENGTH}} + {{WIDTH}}) %>% 
    filter(sum > 4) %>% 
    nrow()
  return(res)
}

filter_rlang(iris, "virginica", Sepal.Length, Sepal.Width)
#> [1] 50

reprex 包于 2019-11-10 创建(v0.3.0)

于 2019-11-11T05:58:58.663 回答