Стандартная оценка для tidyr::complete - функция, которая завершается всеми нечисловыми столбцами

Я хочу сделать функцию, которая будет применять tidyr::complete ко всем нечисловым столбцам в R data.frame. Нулевое значение должно быть вставлено в новые строки значений. Я понимаю, что для этого требуется стандартное решение для оценки, но я пока не добился успеха.

Вот что я имею до сих пор:

completeDf <- function(df){

      vars <- names(df)

      chVars <- vars[!(sapply(df, is.numeric))]
      nmVars <- vars[!(vars %in% chVars)]

      quoChVars <- quos(chVars)

      nmList <- vector("list", length(nmVars))
      nmList <- setNames(lapply(nmList, function(x) x <- 0), nmVars)
      quoNmVars <- quos(nmList)

      df <- df %>%
            complete(!!!quoChVars, fill = !!!quoNmVars)
}

Есть идеи, как заставить это работать?

1 ответ

Решение

1) Использование Rlang/ Tidyreval !!!syms(notnum_names) вставить имена переменных как complete аргументы. Fill это просто обычный список, и для него не требуются вычисления в rlang/tidyeval.

library(dplyr)
library(tidyr)
library(rlang)

completeDF <- function(data) {
  is_num <- sapply(data, is.numeric)
  num_names <- names(data)[ is_num ]
  notnum_names <- names(data)[ !is_num ]
  fill <- Map(function(x) 0, num_names)
  data %>% complete(!!!syms(notnum_names), fill = fill)
}

DF <- data.frame(a = c("A", "B", "B"), b = c("a", "a", "b"), c = 1:3) # test data
completeDF(DF)

давая:

# A tibble: 4 x 3
       a      b     c
  <fctr> <fctr> <dbl>
1      A      a     1
2      A      b     0
3      B      a     2
4      B      b     3

Вот оригинальный код вопроса, модифицированный, чтобы он работал. Измененные строки отмечены ## в конце каждой.

completeDf <- function(df){

      vars <- names(df)

      chVars <- vars[!(sapply(df, is.numeric))]
      nmVars <- vars[!(vars %in% chVars)]

      symsChVars <- rlang::syms(chVars) ##

      nmList <- vector("list", length(nmVars))
      nmList <- setNames(lapply(nmList, function(x) 0), nmVars) ##
      # quoNmVars <- quos(nmList ##

      df %>% ##
            complete(!!!symsChVars, fill = nmList) ##
}

completeDf(DF)

2) wrapr Альтернативой rlang/tidyeval является пакет wrapr.

Код здесь такой же, как в (1), за исключением того, что мы используем library(wrapr) вместо library(rlang) и последняя строка completeDF заменяется на let предоставление заявления completeDF2,

library(dplyr)
library(tidyr)
library(wrapr)

completeDF2 <- function(data) {
  is_num <- sapply(data, is.numeric)
  num_names <- names(data)[ is_num ]
  notnum_names <- names(data)[ !is_num ]
  fill <- Map(function(x) 0, num_names)
  let(c(NOTNUM = toString(notnum_names)), 
      data %>% complete(NOTNUM, fill = fill),
      strict = FALSE,
      subsMethod = "stringsubs")
}

completeDF2(DF)

Обновления: исправления и улучшения. Добавить обертку подход.

Другие вопросы по тегам