Имена динамических переменных для изменения переменных в цикле for

#r #for-loop #variables #dynamic

Вопрос:

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

 # Example data:
var0 = c(1, 2, 2, 1, 1, 2, 2)
var1 = c(NA, 1, 0, 1, 0, NA, 4444)
var2 = c(1, NA, 0, 0, 1, 4444, NA)
var3 = c(NA, 1, 0, 4444, 1, NA, 1)

df1 <- data.frame(var0, var1, var2, var3)

# Data:
  var0 var1 var2 var3
1    1   NA    1   NA
2    2    1   NA    1
3    2    0    0    0
4    1    1    0 4444
5    1    0    1    1
6    2   NA 4444    0
7    2 4444   NA    1

 

Это моя функция и для цикла:

 vars = c("var1", "var2")

func <- function(i) {
  mutate(df1, !!i := case_when(!is.na(i) ~ i,
                             is.na(i) amp; var0 != '1' ~ '4444',
                             TRUE ~ '0'))
}

for(i in vars) {
  df2 <- func(i)
}

test <- df2 %>%
  select(var1, var3) #leaving var3 unchanged to test in comparison
 

Вот как я хотел бы, чтобы результат выглядел:

   var0 var1 var2 var3
1    1    0    1   NA
2    2    1 4444    1
3    2    0    0    0
4    1    1    0 4444
5    1    0    1    1
6    2 4444 4444   NA
7    1 4444    0    1
 

Ответ №1:

Когда мы передаем строку, преобразуйте ее в sym бол и оцените ( !! )

 func <- function(i) {
   
   mutate(df1, !!i := case_when(!is.na(!! rlang::ensym(i)) ~ as.character(!! rlang::ensym(i)),
                              is.na(!!rlang::ensym(i)) amp; var0 != '1' ~ '4444',
                              TRUE ~ '0'))
 }

 

-тестирование

 for(i in vars) {
   df1 <- func(i)
 }
df1
  var0 var1 var2 var3
1    1    0    1   NA
2    2    1 4444    1
3    2    0    0    0
4    1    1    0 4444
5    1    0    1    1
6    2 4444 4444   NA
7    2 4444 4444    1  
 

Мы можем сделать это и с across помощью

 df1 %>%
    mutate(across(all_of(vars), 
    ~ case_when(!is.na(.) ~ as.character(.), 
       is.na(.) amp; var0 != '1' ~ '4444', TRUE ~ '0')))
  var0 var1 var2 var3
1    1    0    1   NA
2    2    1 4444    1
3    2    0    0    0
4    1    1    0 4444
5    1    0    1    1
6    2 4444 4444   NA
7    2 4444 4444    1
 

Ответ №2:

Вы можете использовать .data при передаче имени столбца в виде строки. Также обновите исходную переменную ( df1 ) вместо создания новой ( df2 ), потому что в функции вы всегда ссылаетесь на исходную переменную ( df1 ).

 library(dplyr)

func <- function(i) {
  mutate(df1, !!i := case_when(!is.na(.data[[i]]) ~ .data[[i]],
                               is.na(.data[[i]]) amp; var0 != 1 ~ 4444,
                               TRUE ~ 0))
}

vars = c("var1", "var2")

for(i in vars) {
  df1 <- func(i)
}

df1

#  var0 var1 var2 var3
#1    1    0    1   NA
#2    2    1 4444    1
#3    2    0    0    0
#4    1    1    0 4444
#5    1    0    1    1
#6    2 4444 4444   NA
#7    2 4444 4444    1