Добавьте отсутствующие столбцы индикатора, используя пакет рецептов tidymodels - PullRequest
3 голосов
/ 28 января 2020

Я хотел бы создать рецепт, используя пакет recipes , который вменяет отсутствующие данные и добавляет столбцы индикатора, которые указывают, какие значения отсутствовали. Также было бы неплохо, если бы была возможность выбора между включением столбца индикатора для каждого столбца в исходном фрейме данных или включением только столбцов индикатора для столбцов, в которых отсутствовали данные в исходном фрейме данных. Я знаю, что могу легко вменить пропущенные значения с помощью рецептов , но есть ли встроенный способ добавления отсутствующих столбцов индикатора?

Например, если у меня был кадр данных, подобный этому:

> data.frame(x = c(1, NA, 3), y = 4:6)
   x y
1  1 4
2 NA 5
3  3 6

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

   x y x_missing
1  1 4     FALSE
2  2 5      TRUE
3  3 6     FALSE

Конечно, для такого простого примера я мог бы сделать это рукой. Но при работе с большим набором данных в конвейере машинного обучения было бы полезно иметь автоматизированный способ сделать это.

Согласно документации для recipes::check_missing, существует аргумент columns,

столбцы Символьная строка имен переменных, которая будет (в конечном итоге) заполнена аргументом term.

, но я не уверен, что это означает, что для check_missing нет аргумента terms.

Для справки, нужная мне функция реализована в scikit-learn с помощью MissingIndicator класс.

1 Ответ

2 голосов
/ 30 января 2020

Это можно сделать, создав пользовательский шаг. Следуя процессу, описанному в одной из виньеток , создайте функции, определяющие шаг, затем определите методы prep и bake для пользовательского шага.

Следующий код определяет новый шаг для создания индикатора отсутствующего значения. Новый столбец добавляется с добавлением суффикса _missing к имени.

step_missing_ind <- function(recipe, 
                             ...,
                             role = NA, 
                             trained = FALSE,
                             columns = NULL,
                             skip = FALSE,
                             id = rand_id("missing_ind")) {
  terms <- ellipse_check(...)
  add_step(
    recipe,
    step_missing_ind_new(
      terms = terms, 
      trained = trained,
      role = role, 
      columns = columns,
      skip = skip,
      id = id
    )
  )
}

step_missing_ind_new <- function(terms, 
                                 role, 
                                 trained, 
                                 columns, 
                                 skip, 
                                 id) {
  step(
    subclass = "missing_ind",
    terms = terms,
    role = role,
    trained = trained,
    columns = columns,
    skip = skip,
    id = id
  )
}

print.step_missing_ind <- function(x, width = max(20, options()$width), ...) {
  cat("Missing indicator on ")
  cat(format_selectors(x$terms, width = width))
  if (x$trained) cat(" [trained]\n") else cat("\n")
  invisible(x)
}

prep.step_missing_ind <- function(x, training, info = NULL, ...) {
  col_names <- terms_select(terms = x$terms, info = info)
  step_missing_ind_new(
    terms = x$terms,
    trained = TRUE,
    role = x$role,
    columns = col_names,
    skip = x$skip,
    id = x$id
  )
}

bake.step_missing_ind <- function(object, new_data, ...) {
  for (var in object$columns) {
    new_data[[paste0(var, "_missing")]] <- is.na(new_data[[var]])
  }
  as_tibble(new_data)
}

Затем мы можем использовать этот шаг отсутствующего индикатора в конвейере рецептов, как в следующем примере, где мы добавляем индикатор отсутствующего значения и выполнить среднее вменение. Порядок отсутствующего индикатора и шагов вменения важен: шаг отсутствующего индикатора должен быть до шага вменения.

library(recipes)

data <- tribble(
  ~x, ~y, ~z,
  1, 4, 7,
  NA, 5, 8,
  3, 6, NA
)

recipe(~ ., data = data) %>%
  step_missing_ind(x, y, z) %>%
  step_meanimpute(x, y, z) %>%
  prep() %>%
  juice()

#> # A tibble: 3 x 6
#>       x     y     z x_missing y_missing z_missing
#>   <dbl> <dbl> <dbl> <lgl>     <lgl>     <lgl>    
#> 1     1     4   7   FALSE     FALSE     FALSE    
#> 2     2     5   8   TRUE      FALSE     FALSE    
#> 3     3     6   7.5 FALSE     FALSE     TRUE
...