Ленивая оценка, если логическое условие

У меня есть следующее data.table:

dtable <- data.table(column1 = c(1, 2, 3, 5, 6, 7, 8),
                     column2 = c(1, 1, 1, 5, 5, 6, 8),
                     column3 = c(7, 8, 9, 0, 9, 2, 3))

Я хотел бы сделать что-то вроде следующей функциональности, но в параметризованной функции:

dtable %>% 
  dplyr::group_by(column1) %>% 
  dplyr::summarise(Result = ifelse(column1 == column2, "A", "B"))

Для этого я создал следующую функцию:

Test <- function(.df, .columnName, .columnToGroup){
  res <- .df %>%
    # This line is interpreted correctly
    dplyr::group_by_(lazyeval::interp(.columnToGroup, .columnToGroup = as.name(.columnToGroup))) %>%

    # This line does not interpret the == condition as a logical one
    dplyr::summarise_(Result = ifelse((lazyeval::interp(.columnToGroup == .columnName,
                                                        .columnToGroup = as.name(.columnToGroup),
                                                        .columnName = as.name(.columnName))),
                                      "A", "B"))
  return(res)
}

Я использую нестандартные функции оценки (group_by_ а также summarise_) в сочетании с lazyeval::interp функция, но == Условие неверно истолковано, и я получаю следующее исключение:

Test(dtable, "column1", "column2")

 Error in UseMethod("interp") : 
  no applicable method for 'interp' applied to an object of class "logical"

Я перепробовал много разных комбинаций (quote, expr_env, as.lazyи т. д.) без удачи. Благодаря этому замечательному Нестандартному руководству по оценке я смог использовать эти lazyeval функции для оценки арифметических выражений ранее, но я не могу найти способ заставить их интерпретировать логическое условие в этом фрагменте кода.

Любая помощь будет принята с благодарностью.

1 ответ

Решение

С ifelseмы можем попробовать (используя @docendodiscimus использование list в комментариях)

Test <- function(.df, .columnName, .columnToGroup){
 .df %>%   
   dplyr::group_by_(.dots = .columnToGroup )%>%
            dplyr::summarise_(.dots =

                            setNames(list(lazyeval::interp(quote(ifelse(colGrp == colName,
                               "A", "B")), .values = list(colGrp = as.name(.columnToGroup),
                                                    colName = as.name(.columnName)))),
                                  "Result"))

 }

res2 <- Test(dtable, "column2", "column1")
identical(res1, res2)
#[1] TRUE

где 'res1'

res1 <- dtable %>% 
          dplyr::group_by(column1) %>% 
          dplyr::summarise(Result = ifelse(column1 == column2, "A", "B"))

Обновить

С новой версией dplyr т.е. 0.6.0 (ожидается релиз в апреле 2017 г.), мы также можем заключить в кавычки group_by а также summarise, enquo функция выполняет ту же работу, что и substitute от base R взяв входной аргумент может создать quosure и это без кавычек (!! или же UQ) в group_by а также summarise для оценки

Test1 <- function(df, colN, colGrp){
      colN <- enquo(colN)
      colGrp <- enquo(colGrp)

      df %>% 
         group_by(!!colGrp) %>%
         summarise(Result = if_else((!!colGrp) == (!!colN), "A", "B"))
}

res3 <- Test1(dtable, column2, column1)
identical(res2, res3)
#[1] TRUE
Другие вопросы по тегам