Как перезаписать уровни нескольких факторных переменных в R, используя цикл for?

#r #loops #for-loop

Вопрос:

У меня есть фрейм данных, в котором есть несколько факторных переменных с одинаковыми уровнями. Перечислил уровни ниже

"Completely Agree (3)" "Do not Agree (1)" "Somewhat Agree (2)"

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

Не согласен и Несколько Согласен должно быть 0

Полностью согласен, должно быть 1

Я попытался использовать следующий код

 for (i in LoopVec.St){
  levels(data[,i]) <- c(1,0,0)
}
 

Лупвек.St содержит имена столбцов всех 18 переменных с одинаковыми уровнями.

levels(data[,i]) <- c(1,0,0) сработало, когда я использовал его для одной переменной. Но когда я использую его в цикле for, он выдает ошибку ниже.

Ошибка в levels<- ( *tmp* , значение = c(1, 0, 0)) : уровень фактора [3] дублируется

Пожалуйста, помогите мне с этим.

Комментарии:

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

2. @Limey — не могли бы вы немного подробнее рассказать об этом?

Ответ №1:

В ответ на запрос ОП в комментариях…

 library(tidyverse)

# Test data.  3 questions just to demonstrate the principle.
d <- tibble(
       Participant=1:10,
       Q1=factor(sample(1:3, 10, TRUE), labels=c("Do not Agree (1)", "Somewhat Agree (2)","Completely Agree (3)")),
       Q2=factor(sample(1:3, 10, TRUE), labels=c("Do not Agree (1)", "Somewhat Agree (2)","Completely Agree (3)")),
       Q3=factor(sample(1:3, 10, TRUE), labels=c("Do not Agree (1)", "Somewhat Agree (2)","Completely Agree (3)"))
)
 

Для перекодирования факторов

 # Recode untidy data
d %>% mutate(
        across(
          starts_with("Q"), 
          function(x) factor(as.numeric(x) == 3, labels=c("Do not completely agree (1amp;2)", "Completely agree (3)"))
        )
      )

# Tidy the data
dTidy <- d %>% 
           pivot_longer(
             cols=starts_with("Q"),
             values_to="Response",
             names_to="Question"
           )
dTidy

# Recode tidy data            
dTidy %>% 
   mutate(
     Response=factor(
                as.numeric(Response) == 3, 
                labels=c("Do not completely agree (1amp;2)", "Completely agree (3)")
              )
   )
 

Пока особой разницы нет. Преимущество аккуратных данных становится более очевидным, когда мы пытаемся что-то с ними сделать. В качестве простого примера постройте гистограмму вопросов. Неопрятные данные не особенно поддаются обработке. Вот простое резюме:

 # Plot untidy data
doPlots <- function(data) {
  print(data %>% ggplot()   geom_bar(aes(x=Q1)))
  print(data %>% ggplot()   geom_bar(aes(x=Q2)))
  print(data %>% ggplot()   geom_bar(aes(x=Q3)))
}

d %>% doPlots()
 

Все остальное довольно неловко. С аккуратными данными все просто:

 # Plot tidy data
dTidy %>% 
  ggplot()  
  geom_bar(aes(x=Response))  
  facet_grid(rows=vars(Question))

# Or
dTidy %>% 
  ggplot()  
  geom_bar(aes(x=Response, fill=Question))
 

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

 # Now add another Question  
d <- d %>% mutate(Q4=factor(sample(1:3, 10, TRUE), labels=c("Do not Agree (1)", "Somewhat Agree (2)", "Completely Agree (3)")))

dTidy  <- dTidy %>% 
            bind_rows(
              tibble(
                Participant=1:10, 
                Question="Q4", 
                Response=factor(sample(1:3, 10, TRUE), labels=c("Do not Agree (1)", "Somewhat Agree (2)", "Completely Agree (3)"))
              )
            )
 

Функцию doPlot необходимо переписать: она игнорирует Q4.

 d %>% doPlot()
 

Но аккуратный код надежен и не нуждается в изменениях

 dTidy %>% 
  ggplot()  
  geom_bar(aes(x=Response))  
  facet_grid(rows=vars(Question))
 

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

  • более компактная
  • легче понять
  • более надежный
  • проще в обслуживании
  • более гибкий

Ответ №2:

Я думаю, вам следует использовать fct_recode() :

 library(tidyverse)
var <- factor(rep(letters[1:3], each = 5))
fct_recode(var, "new1" = "a", "new2" = "b", "new2" = "c")

#> [1] new1 new1 new1 new1 new1 new2 new2 new2 new2 new2 new2 new2 new2 new2 new2
#> Levels: new1 new2
 

для получения дополнительной информации, например, проверьте книгу r4ds.

Комментарии:

1. Привет, я уже пробовал это. Опять же, это работает, если я запускаю его индивидуально, но при выполнении с использованием цикла for он выдает следующую ошибку. >Ошибка: > f должен быть фактор (или вектор символов).

Ответ №3:

Вы используете коэффициент функции следующим образом:

 data[,i] = factor(data[,i], 
                  levels= c("Do not Agree (1)",
                            "Somewhat Agree (2)",
                            "Completely Agree (3)"
                  ))
 

Вы также можете проверить различные функции выравнивания tidyverse . Например fct_relevel , функция.
https://forcats.tidyverse.org/reference/fct_relevel.html

Комментарии:

1. Я не пытаюсь здесь соотнести факторы. Скорее, я пытаюсь их перекодировать. Я хочу объединить уровни, которые Несколько Согласны и не согласны, и закодировать их как 0 и Полностью согласиться с 1.