Почему mutate_at не создает другое имя для нового столбца, когда я передаю ему только один столбец в vars ()? - PullRequest
3 голосов
/ 02 апреля 2020

Я заметил неожиданное поведение mutate_at. Предположим, у меня есть фрейм данных и список столбцов, которые я хочу изменить, например:

df1 <- data_frame(var1 = c(1,2,3,4,5,6),
                  var2 = c(1,1,1,2,2,2),
                  var3 = c(10,30,50,70,90,110))
variables <- c("var1", "var2")

Теперь я применяю mutate_at для создания новых факторных версий столбцов, определенных в variables. Указывая «cat» в list, я проверяю, сохраняются ли старые версии, а новые версии имеют имя старой версии плюс «_cat»:

df1 %>% mutate_at(vars(variables), .funs = list(cat = as.factor))
# A tibble: 6 x 5
   var1  var2  var3 var1_cat var2_cat
  <dbl> <dbl> <dbl> <fct>    <fct>   
1     1     1    10 1        1       
2     2     1    30 2        1       
3     3     1    50 3        1       
4     4     2    70 4        2       
5     5     2    90 5        2       
6     6     2   110 6        2  

Однако, если я применяю mutate_at только к одному столбцу (в моем случае мой variables вектор имеет только один элемент), имя новой переменной - только "cat":

variables <- c("var1")
df1 %>% mutate_at(vars(variables), .funs = list(cat = as.factor))
# A tibble: 6 x 4
   var1  var2  var3 cat  
  <dbl> <dbl> <dbl> <fct>
1     1     1    10 1    
2     2     1    30 2    
3     3     1    50 3    
4     4     2    70 4    
5     5     2    90 5    
6     6     2   110 6  

На каком-то уровне я понимаю почему mutate_at делает это: если вы хотите назвать один столбец с каким-либо измененным именем каким-либо особым образом, просто используйте mutate как mutate(var1_cat = as.factor(var1)).

Однако в моем случае я хочу запустить mutate_at работа над несколькими кадрами данных, для каждого из которых у меня есть вектор столбцов для изменения. Важно отметить, что эти векторы могут иметь только один элемент. Итак, не лучше ли для mutate_at показать одинаковое поведение именования независимо от того, сколько vars он получает?

Ответы [ 2 ]

7 голосов
/ 02 апреля 2020

Я не думаю, что это ожидаемое поведение (или, по крайней мере, не должно), и хорошая новость заключается в том, что новейшая версия dplyr избавляется от этого поведения. В настоящее время вы можете установить его с помощью remotes::install_github('tidyverse/dplyr'), но в следующем месяце он должен быть на CRAN или 2.

mutate_at (и других глаголах с ограниченным диапазоном, таких как mutate_if, summarize_all, et c. ) был заменен использованием across в существующих глаголах, и это обеспечивает поведение, которое вы ищете.

library(dplyr)

variables <- c("var1", "var2")

df1 %>% 
  mutate(across(all_of(variables), .fns = list(cat = as.factor)))
#> # A tibble: 6 x 5
#>    var1  var2  var3 var1_cat var2_cat
#>   <dbl> <dbl> <dbl> <fct>    <fct>   
#> 1     1     1    10 1        1       
#> 2     2     1    30 2        1       
#> 3     3     1    50 3        1       
#> 4     4     2    70 4        2       
#> 5     5     2    90 5        2       
#> 6     6     2   110 6        2

variables <- c("var1")

df1 %>% 
  mutate(across(all_of(variables), .fns = list(cat = as.factor)))
#> # A tibble: 6 x 4
#>    var1  var2  var3 var1_cat
#>   <dbl> <dbl> <dbl> <fct>   
#> 1     1     1    10 1       
#> 2     2     1    30 2       
#> 3     3     1    50 3       
#> 4     4     2    70 4       
#> 5     5     2    90 5       
#> 6     6     2   110 6

Информация о сеансе

sessionInfo()
#> R version 3.6.3 (2020-02-29)
#> Platform: x86_64-w64-mingw32/x64 (64-bit)
#> Running under: Windows 10 x64 (build 17763)
#> 
#> Matrix products: default
#> 
#> locale:
#> [1] LC_COLLATE=English_United Kingdom.1252 
#> [2] LC_CTYPE=English_United Kingdom.1252   
#> [3] LC_MONETARY=English_United Kingdom.1252
#> [4] LC_NUMERIC=C                           
#> [5] LC_TIME=English_United Kingdom.1252    
#> 
#> attached base packages:
#> [1] stats     graphics  grDevices utils     datasets  methods   base     
#> 
#> other attached packages:
#> [1] dplyr_0.8.99.9001
#>
#> loaded via a namespace (and not attached):
#>  [1] Rcpp_1.0.3        knitr_1.28        magrittr_1.5      tidyselect_1.0.0 
#>  [5] R6_2.4.1          rlang_0.4.5.9000  fansi_0.4.1       stringr_1.4.0    
#>  [9] highr_0.8         tools_3.6.3       xfun_0.12         utf8_1.1.4       
#> [13] cli_2.0.2         htmltools_0.4.0   ellipsis_0.3.0    assertthat_0.2.1 
#> [17] yaml_2.2.1        digest_0.6.25     tibble_2.1.3      lifecycle_0.2.0  
#> [21] crayon_1.3.4      purrr_0.3.3       vctrs_0.2.99.9010 glue_1.3.2       
#> [25] evaluate_0.14     rmarkdown_2.1     stringi_1.4.6     compiler_3.6.3   
#> [29] pillar_1.4.3      pkgconfig_2.0.3
2 голосов
/ 02 апреля 2020

Не уверен, есть ли простое решение для этого.

Однако одним из способов будет применение этой функции на основе length из variables.

library(dplyr)

if (length(variables) > 1) {
   df1 %>% mutate_at(vars(variables), list(cat = as.factor))
} else {
   df1 %>% mutate(!!paste0(variables, "_cat") := as.factor(!!sym(variables)))
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...