аргументы функции для mutate_if в dplyr работают для funs () с мягкой амортизацией, но не для list ()

Я пытаюсь обновить следующий код, потому что funs( MY_FUN ) мягко обесценивается. Я знаю, что заменой этого должно быть list( ~MY_FUN ), но, похоже, это не работает для моего кода.

Вот мои фреймы данных:

fake_data <- data.frame(var1 = rep("TEMP", times = 5),
                        var2 = rep("TEMP", times = 5),
                        var3 = c(1:5),
                        stringsAsFactors = FALSE)

lookup_sub <- data.frame(var_names = c("var1", "var2", "var3"),
                         example_value = c("a", "b", "c"),
                         stringsAsFactors = FALSE)

Следующая строка кода работает и делает именно то, что я хочу:

library(tidyverse)
library(rlang)
fake_data %>%
        mutate_if(.predicate = rlang::as_function(function(x){identical("TEMP", unique(x))}),
                  .funs = funs(as.character((lookup_sub %>% filter(var_names == quo_name(quo(.))) %>% pull(example_value))[1])))

В результате чего

  var1 var2 var3
1    a    b    1
2    a    b    2
3    a    b    3
4    a    b    4
5    a    b    5

НО с использованием аргумента без обесценения дает все значения NA строкам, которые оцениваются как TRUE в предикате

fake_data %>%
        mutate_if(.predicate = rlang::as_function(function(x){identical("TEMP", unique(x))}),
                  .funs = list(~as.character((lookup_sub %>% filter(var_names == quo_name(quo(.))) %>% pull(example_value))[1])))

что приводит к

  var1 var2 var3
1 <NA> <NA>    1
2 <NA> <NA>    2
3 <NA> <NA>    3
4 <NA> <NA>    4
5 <NA> <NA>    5

Кто-нибудь может мне это объяснить? Я знаю, что проблема возникает из-за quo_name(quo(.)), но не знаю, как ее исправить. Спасибо!


person Voy    schedule 12.03.2020    source источник
comment
Обратите внимание, что в предикате можно использовать лямбда-функции: .predicate = ~identical("TEMP", unique(.x))   -  person Dan Chaltiel    schedule 12.03.2020
comment
возможно, стоит взглянуть на новую версию dplyr (возможно, все еще только на github, а не на CRAN), в которой есть новая функция across для этого типа проблемы   -  person Richard Telford    schedule 12.03.2020
comment
Тем не менее, это похоже на ошибку, поскольку некогда поддерживаемая функция больше не используется. Вы можете разместить это на github dplyr   -  person Dan Chaltiel    schedule 13.03.2020


Ответы (1)


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

Считайте эти фальшивые данные

smooth_data <- data.frame(`s(gam_variable_1_output)` = c(1.004, 1.345, 1.460, 1.540),
                          `s(gam_variable
smooth_data %>%
mutate_if(.predicate = funs(length(unique(.)) != 1 & grepl("s\\(", quo_name(quo(.)))),
          ~2) # we'll use this for example
output)` = c(1, 1, 1, 1), grouping_variable_1 = c(1,2,3,4), grouping_variable_2 = c("a", "b", "a", "b"), grouping_variable_3 = c(500, 500, 500, 500), stringsAsFactors = FALSE)

Я хочу применить функцию ко всем гладким переменным (переменным, которые начинаются с "s ("), только если уровни этой гладкой переменной не имеют 1 уникального значения.

Это должно быть выполнено с помощью следующих

smooth_data %>%
mutate_if(.predicate = funs(length(unique(.)) != 1 & grepl("s\\(", quo_name(quo(.)))),
          ~2) # we'll use this for example

Таким образом, это должно привести к следующему (я удалил имена / числа строк из вывода R)

s(gam_variable_1_output)
                       2
                       2
                       2
                       2
s(gam_variable_2_output)
                       1
                       1
                       1
                       1
grouping_variable_1       grouping_variable_2       grouping_variable_3
                  1                       "a"                       500
                  2                       "b"                       500
                  3                       "a"                       500
                  4                       "b"                       500

Но функция не работает. Если мы хотим разделить предикат на части, мы увидим кое-что интересное.

#### FIRST PART OF CONDITIONAL: only look at variables that arent a single value
## THIS WORKS
smooth_data %>% mutate_if(funs(length(unique(.)) != 1), ~2)
## ^ THAT IS THE SAME AS THIS; THIS WORKS
smooth_data %>% mutate_if(~length(unique(.)) != 1, ~2)
## THIS DOES NOT WORK
smooth_data %>% mutate_if(length(unique(.)) != 1, ~2)


#### SECOND PART OF CONDITIONAL: only look at variables that have name including `s(`
## THIS WORKS
smooth_data %>% mutate_if(grepl("s\\(", names(.)), ~2)

## THIS THROWS ERROR (BECAUSE OF `names(.)`)
smooth_data %>% mutate_if(~grepl("s\\(", names(.)), ~2)

## THIS DOES NOT WORK
smooth_data %>% mutate_if(~grepl("s\\(", quo_name(quo(.))), ~2)

## WHICH IS THE SAME AS THIS
smooth_data %>% mutate_if(funs(grepl("s\\(", quo_name(quo(.)))), ~2)

## AND THIS THROWS ERROR (BECAUSE IT NEEDS ~)
smooth_data %>% mutate_if(grepl("s\\(", quo_name(quo(.))), ~2)

Это интересно, потому что это подсказывает мне, что моя основная строка кода не может работать, поскольку первая часть условного выражения должна быть в настройке funs (), а вторая часть не может быть в настройке funs (). Это не ответ на вопрос, но я думаю, что он ясно показывает проблему с mutate_if

person Voy    schedule 24.03.2020