Создайте функцию (которая использует data.table), которая поддерживает аргументы в кавычках и без кавычек, а затем работает в purrr :: map (или lapply) - PullRequest
1 голос
/ 02 мая 2020

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

library(data.table) # version 1.11.8
library(purrr)

col_count <- function(dt, vars = NULL){
  dt[, .N, by = vars]
}

Я успешно создал в основном одну и ту же функцию, которая способна принимать переменные как в кавычках, так и без кавычек (благодаря аргументу 'by' в data.table, который получает список или символьный вектор).

col_count2 <- function(dt, ...){
  vars <- NULL
  try(if(is.character(...)) {vars <- unlist(eval(substitute(...)))}, silent = TRUE)

  if(is.null(vars)) vars <- substitute(list(...))

  dt[, .N, by = vars]
}
dt_iris <- data.table::as.data.table(iris)

identical(col_count2(dt_iris, Petal.Width, Species), 
          col_count2(dt_iris, c('Petal.Width', 'Species')))
[1] TRUE

Теперь я хочу, чтобы мою функцию можно было повторять с помощью purrr :: map (или lapply) следующим образом:

purrr::map(colnames(dt_iris), ~ col_count(dt_iris, .))

, которая работает.

Но

purrr::map(colnames(dt_iris), ~ col_count2(dt_iris, .))
Error in eval(bysub, x, parent.frame()) : object '.' not found 

Это сообщение из data.table, которое получает '.' в качестве переменной vars в выражении «by =». purrr :: map отправляет '.' и так как это не символ, он идет прямо к:

vars <- substitute(list(...))

Я предполагаю, что есть лучший способ решить проблему с кавычками / кавычками и оставаться в пределах data.table.

1 Ответ

2 голосов
/ 02 мая 2020

Мы можем использовать:

library(data.table)

col_count2 <- function(dt, ...){
   vars <- NULL 
   tryCatch({vars <- list(...)[[1]]}, error = function(e) {})
   if(!is.character(vars)) vars <- as.character(substitute(list(...))[-1])
   dt[, .N, by = vars]
}

identical(col_count2(dt_iris, Petal.Width, Species), 
          col_count2(dt_iris, c('Petal.Width', 'Species')))
#[1] TRUE

purrr::map(colnames(dt_iris), col_count2, dt = dt_iris)

#[[1]]
#    Sepal.Length  N
# 1:          5.1  9
# 2:          4.9  6
# 3:          4.7  2
# 4:          4.6  4
#....

#[[2]]
#    Sepal.Width  N
# 1:         3.5  6
# 2:         3.0 26
# 3:         3.2 13
# 4:         3.1 11
#....
#....
...