【问题标题】:how to write a for loop in R that recodes multiple variables?如何在 R 中编写一个重新编码多个变量的 for 循环?
【发布时间】:2021-02-17 09:35:21
【问题描述】:

我是一名自学成才的程序员,在 MATLAB 方面有几年的经验。我是 R 的新手,这是我在 Stack Overflow 上的第一个问题。

我正在尝试使用来自 dplyr 的 recode 重新编码数据框中的多个变量。在下面的代码中,我提供了一个 data 的 sn-p 和我想与 recode 一起使用的选项列表 opt_dass。我想将每个变量中以“dass”开头的字符串值转换为数字 - 从不 = 0,有时 = 1,等等。

我知道有多种方法可以解决这个问题,包括ifelselapplycase_when。在下面的示例中,我想知道为什么会收到有关非语言对象的错误。我正在使用paste0 创建要在data 中引用的变量名。我已经阅读了大量有关如何在 R 中的 for 循环中引用列名的信息,但我仍然没有找到答案。

library(tidyverse)

data <- structure(list(id = c("1", "2", "3", "4", "5", "6", "7", "8", 
                              "9", "11"), dass1_t1 = c("Sometimes", "Often", "Often", "Almost Always", 
                                                       "Sometimes", "Sometimes", "Sometimes", "Sometimes", "Sometimes", 
                                                       "Sometimes"), dass2_t1 = c("Sometimes", "Never", "Often", "Sometimes", 
                                                                                  "Sometimes", "Never", "Sometimes", "Sometimes", "Often", "Sometimes"
                                                       ), dass3_t1 = c("Often", "Sometimes", "Never", "Never", "Never", 
                                                                       "Sometimes", "Never", "Never", "Sometimes", "Sometimes"), dass4_t1 = c("Never", 
                                                                                                                                              "Never", "Never", "Never", "Never", "Sometimes", "Never", "Never", 
                                                                                                                                              "Never", "Sometimes"), dass5_t1 = c("Almost Always", "Sometimes", 
                                                                                                                                                                                  "Never", "Sometimes", "Never", "Sometimes", "Sometimes", "Never", 
                                                                                                                                                                                  "Almost Always", "Often")), row.names = c(NA, -10L), class = "data.frame")

opt_dass <- list("Never"=0,"Sometimes"=1,"Often"=2,"Almost Always"=3) # list - chr to num

# my attempt at a for loop to recode
for (i in 1:5) {
  attach(data)
  paste0("dass_", i, "_t1") <- recode(paste0("dass_", i, "_t1"), !!!opt_dass, .default=NA_real_)
}

#> Error in paste0("dass_", i, "_t1") <- recode(paste0("dass_", i, "_t1"), : target of assignment expands to non-language object

reprex package (v0.3.0) 于 2020 年 11 月 4 日创建

额外问题:有没有办法编写一个for 循环,可以完成对具有不同选项集的多组变量进行重新编码?我有一个包含多个自我报告度量的数据集,其中不同的字符串响应具有不同的数值。我认为这将涉及一些元编程,并且很想听听您的想法!

【问题讨论】:

    标签: r for-loop dplyr recode


    【解决方案1】:

    首先,使用命名向量而不是命名列表

    opt_dass <- c("Never"=0,"Sometimes"=1,"Often"=2,"Almost Always"=3)
    

    那么就

    mutate(data, across(starts_with("dass"), ~unname(opt_dass[.])))
    

    输出

       id dass1_t1 dass2_t1 dass3_t1 dass4_t1 dass5_t1
    1   1        1        1        2        0        3
    2   2        2        0        1        0        1
    3   3        2        2        0        0        0
    4   4        3        1        0        0        1
    5   5        1        1        0        0        0
    6   6        1        0        1        1        1
    7   7        1        1        0        0        1
    8   8        1        1        0        0        0
    9   9        1        2        1        0        3
    10 11        1        1        1        1        2
    

    【讨论】:

      【解决方案2】:

      我可能只是将它们设为因数,然后使用底层整数代码(减 1):

      data %>%
          mutate_at(.vars = vars(starts_with("dass")),
                              .funs = ~factor(x = .,levels = c("Never","Sometimes","Often","Almost Always"))) %>%
          mutate_at(.vars = vars(starts_with("dass")),
                              .funs = ~as.integer(.) - 1)
      

      【讨论】:

        【解决方案3】:

        从宽到长重塑,重新编码,然后再从长到宽重塑:

        pivot_longer(data, cols = -1) %>% 
          mutate(value = recode(value, "Never"=0,"Sometimes"=1,
                                "Often"=2,"Almost Always"=3)) %>% 
          pivot_wider(., id_cols = "id")
        
        # # A tibble: 10 x 6
        #    id    dass1_t1 dass2_t1 dass3_t1 dass4_t1 dass5_t1
        #    <chr>    <dbl>    <dbl>    <dbl>    <dbl>    <dbl>
        #  1 1            1        1        2        0        3
        #  2 2            2        0        1        0        1
        #  3 3            2        2        0        0        0
        #  4 4            3        1        0        0        1
        #  5 5            1        1        0        0        0
        #  6 6            1        0        1        1        1
        #  7 7            1        1        0        0        1
        #  8 8            1        1        0        0        0
        #  9 9            1        2        1        0        3
        # 10 11           1        1        1        1        2
        

        【讨论】:

          【解决方案4】:

          我真的很喜欢 qdapTools 包中的 lookup() 函数用于重新编码。以下是如何将它用于您的用例:

          library(tidyverse)
          library(qdapTools)
          
          data <- structure(
            list(
              id = c("1", "2", "3", "4", "5", "6", "7", "8", "9", "11"),
              dass1_t1 = c(
                "Sometimes", "Often", "Often", "Almost Always", "Sometimes", "Sometimes",
                "Sometimes", "Sometimes", "Sometimes", "Sometimes"
              ),
              dass2_t1 = c(
                "Sometimes", "Never", "Often", "Sometimes", "Sometimes", "Never", 
                "Sometimes", "Sometimes", "Often", "Sometimes"
              ),
              dass3_t1 = c(
                "Often", "Sometimes", "Never", "Never", "Never", "Sometimes", "Never",
                "Never", "Sometimes", "Sometimes"
              ),
              dass4_t1 = c(
                "Never", "Never", "Never", "Never", "Never", "Sometimes", "Never", 
                "Never", "Never", "Sometimes"
              ),
              dass5_t1 = c(
                "Almost Always", "Sometimes", "Never", "Sometimes", "Never", "Sometimes",
                "Sometimes", "Never", "Almost Always", "Often"
              )
            ),
            row.names = c(NA, -10L),
            class = "data.frame"
          )
          
          opt_dass <- list(
            `0` = "Never", `1` = "Sometimes", `2` = "Often", `3` = "Almost Always"
          )
          
          data %>% 
            mutate(across(dass1_t1:dass5_t1, ~ as.numeric(lookup(.x, opt_dass))))
          #>    id dass1_t1 dass2_t1 dass3_t1 dass4_t1 dass5_t1
          #> 1   1        1        1        2        0        3
          #> 2   2        2        0        1        0        1
          #> 3   3        2        2        0        0        0
          #> 4   4        3        1        0        0        1
          #> 5   5        1        1        0        0        0
          #> 6   6        1        0        1        1        1
          #> 7   7        1        1        0        0        1
          #> 8   8        1        1        0        0        0
          #> 9   9        1        2        1        0        3
          #> 10 11        1        1        1        1        2
          

          reprex package (v0.3.0) 于 2020 年 11 月 4 日创建

          要了解有关lookup() 功能的更多信息,请查看qdapTool's reference manual

          【讨论】:

            【解决方案5】:

            您看到的错误是因为您不能使用表达式来构建 要分配给&lt;- 左侧的变量的名称。更多 详情见this answer

            要重新编码多个变量,您可以存储重新编码映射 在一个命名列表中,其中包含您要重新编码的每个变量的元素:

            recodes <- list(
              q1 = c(a = 1, b = 2, c = 3),
              q2 = c(x = 9, y = 8, z = 7)
            )
            
            tbl <- data.frame(
              id = c(1, 2, 3),
              q1 = c("b", "a", "c"),
              q2 = c("z", "z", "x")
            )
            
            tbl
            #>   id q1 q2
            #> 1  1  b  z
            #> 2  2  a  z
            #> 3  3  c  x
            

            然后遍历数据中的变量,并选择重新编码映射 根据变量名从列表中使用:

            for (variable in names(tbl)) {
              if (!variable %in% names(recodes)) {
                next # skip if the variable isn't recoded
              }
              
              new_variable <- paste0(variable, "n")
              
              old_value <- tbl[[variable]]
              new_value <- recodes[[variable]][old_value]
              
              tbl[[new_variable]] <- new_value
            }
            
            tbl
            #>   id q1 q2 q1n q2n
            #> 1  1  b  z   2   7
            #> 2  2  a  z   1   7
            #> 3  3  c  x   3   9
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2015-11-01
              • 2022-06-15
              • 1970-01-01
              • 2018-07-18
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多