Создание функции tidyeval внутри case_when - PullRequest
3 голосов
/ 16 октября 2019

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

library(tidyverse)
library(janitor)

dummy1 <- runif(5000, 0, 1)
dummy11 <- case_when(
    dummy1 < 0.776 ~ 1,
    dummy1 < 0.776 + 0.124 ~ 2,
    TRUE ~ 5)

df1 <- tibble(q1 = dummy11)

вот результат:

df1 %>% tabyl(q1)
 q1    n percent
  1 3888  0.7776
  2  605  0.1210
  5  507  0.1014

Я использовал mutate и sample, чтобы разделить значение = 5 среди значений 1 и 2, как это:

df1 %>%
    mutate(q1 = case_when(q1 == 5 ~ sample(
        2,
        length(q1),
        prob = c(0.7776, 0.1210),
        replace = TRUE
    ),
    TRUE ~ as.integer(q1))
    )

и вот результат:

q1    n percent
  1 4322  0.8644
  2  678  0.1356

Этот подход кажется работающим, однако, поскольку мне нужно применить это для нескольких переменных, я попытался написать функцию, которая работает с tidyverseс tidyeval, вот так

    my_impute <- function(.data, .prob_var, ...) {
        .prob_var <- enquo(.prob_var)

        .data %>%
            sample(2, prob=c(!!.prob_var), replace = TRUE) 
    }

# running on data 
df1 %>%
    mutate(q1 = case_when(q1 == 5 ~ !!my_impute(q1),
    TRUE ~ as.integer(q1))
    )

Ошибка:

Error in eval_tidy(pair$lhs, env = default_env) : object 'q1' not found

Ответы [ 2 ]

2 голосов
/ 16 октября 2019

Нам нужны значения prob из столбца «процентов», сгенерированные из tabyl, поэтому функцию можно изменить на

library(janitor)
library(dplyr)

my_impute <- function(.data, .prob_var, vals, ...) {
        .prob_var = enquo(.prob_var)
        .prob_vals <- .data %>%
             janitor::tabyl(!!.prob_var) %>%
             filter(!!.prob_var %in% vals) %>%
             pull(percent)

         .data %>%
              mutate(!! .prob_var := case_when(!! .prob_var == 5 ~ 
                sample(
                        2,
                        n(),
                        prob = .prob_vals,
                        replace = TRUE
                    ),
                    TRUE ~ as.integer(q1))
                    )
    }


df1 %>% 
     my_impute(q1, vals = 1:2) %>%
     tabyl(q1)
# q1    n percent
# 1 4285   0.857
# 2  715   0.143
1 голос
/ 17 октября 2019

Просто, чтобы добавить мои два цента, новая версия rlang позволяет заменить процесс квази-цитаты: enquo () + !! и вы можете использовать curly-curly для охвата переменных: функция будет выглядеть так:

my_impute <- function(.data, .prob_var, vals, ...) {

  #.prob_var = enquo(.prob_var)
  # commented out since it is no longer needed
  .prob_vals <- .data %>%
    janitor::tabyl({{.prob_var}}) %>%
    filter({{.prob_var}} %in% {{vals}}) %>%
    pull(percent)

  .data %>%
    mutate( {{.prob_var}} := case_when( {{.prob_var}} == 5 ~ 
                                       sample(
                                         2,
                                         n(),
                                         prob = {{.prob_vals}},
                                         replace = TRUE
                                       ),
                                     TRUE ~ as.integer(q1))
    )
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...