【问题标题】:Recoding several variables in for loop在 for 循环中重新编码几个变量
【发布时间】:2021-07-19 21:18:17
【问题描述】:

我正在处理一些调查数据,其中一些响应的编码不一致。例如,“我不知道”可以编码为 4、5、97 或 777。我想尽可能高效地将所有这些响应标准化为“77”。我想使用人行横道,并希望避免为发生这种情况的每个变量创建一个新的重新编码命令,如果可能的话,因为有几个。

library(tidyverse)

#df with the inconsistent fourth category
var1 <- c("1", "2", "3", "4")
var2 <- c("1", "2", "3", "5")
var3 <- c("1", "2", "3", "97")
var4 <- c("1", "2", "3", "777")

df <- data.frame(var1, var2, var3, var4)

var <- c("var1", "var2", "var3", "var4")
oldvalue <- c("4", "6", "97", "777")
newvalue <- c("77", "77", "77", "77")

#crosswalk of old values to new values
cw <- data.frame(var, oldvalue, newvalue)

recodevars = cw$var

我尝试过的一些事情如下,虽然我没有任何运气。如果您有任何建议,请告诉我。

rec_all = df %>%
  transmute_at(vars(recodevars), funs(recode(., cw$oldvalue = cw$newvalue)))


for(i in recodevars){
  rec_all = df %>%
    transmute_at(vars(recodevars), funs(ifelse(i == cw$oldval, cw$newval, i)))
}

【问题讨论】:

    标签: r tidyverse dplyr recode


    【解决方案1】:

    循环across“recodevars”列,根据列名 (cur_column()) 对“cw”数据集行进行子集化,同时删除第一列,使用它来匹配和替换数据的值,然后 @ 987654323@ 与原始列,以便将不匹配的NA 元素替换为相应的原始列值

    library(dplyr)
    library(tibble)
    df %>% 
        mutate(across(all_of(recodevars), 
           ~ coalesce(deframe(cw[cw$var ==cur_column(),][-1])[as.character(.)], .)))
    

    -输出

      var1 var2 var3 var4
    1    1    1    1    1
    2    2    2    2    2
    3    3    3    3    3
    4   77    5   77   77
    

    【讨论】:

      【解决方案2】:

      如果值独立于您的示例中的列,那么您可以简单地使用以下代码:

      df %>%
          dplyr::mutate(across(everything(), ~ ifelse(.x %in% c(4,6,97,777), 77, .x)))
      

      【讨论】:

        【解决方案3】:

        虽然不是 tidyverse 的一部分 apply 是旧的标准函数,用于将函数应用于 data.frame 中的任何值,基本上使它成为一个单行:

        var1 <- c("1", "2", "3", "4")
        var2 <- c("1", "2", "3", "5")
        var3 <- c("1", "2", "3", "97")
        var4 <- c("1", "2", "3", "777")
        
        df <- data.frame(var1, var2, var3, var4)
        
        var <- c("var1", "var2", "var3", "var4")
        oldvalue <- c("4", "6", "97", "777")
        
        new.df <- apply(df[, var], 1:2, function(x) if(x %in% oldvalue) 77 else x)
        
        print(new.df)
        

        【讨论】:

          【解决方案4】:

          如果您处理的是因子(“1”)而不是数字响应(1),forcats 包可能是您的朋友。

          这会将 notForRecode 字符串中没有的任何内容重新编码为“77”

          notForRecode <- c("1", "2", "3") #  Add others as wanted
          df <- df %>% 
            mutate(across(everything(), ~ fct_other(.x, keep = notForRecode, other_level = "77")))
          

          【讨论】:

            【解决方案5】:

            基本 R 选项

            setNames(list2DF(
                lapply(
                    names(df),
                    function(k) {
                        with(
                            cw,
                            replace(df[[k]], df[[k]] == oldvalue[var == k], newvalue[var == k])
                        )
                    }
                )
            ), names(df))
            

            给予

              var1 var2 var3 var4
            1    1    1    1    1
            2    2    2    2    2
            3    3    3    3    3
            4   77    5   77   77
            

            【讨论】:

              【解决方案6】:

              使用purrr::pmap_dfc -

              purrr::pmap_dfc(cw, ~{
                tmp <- df[..1]
                tmp[tmp == ..2] <- ..3
                tmp
              })
              
              #  var1 var2 var3 var4
              #1    1    1    1    1
              #2    2    2    2    2
              #3    3    3    3    3
              #4   77    5   77   77
              

              【讨论】:

              • 感谢您的回答。这对我来说效果很好,但是当我有一个正在更改两个或多个元素的变量时,它会给我两列而不是更改同一列中的两个元素。我对purrr不是很熟悉,你知道有没有办法解决这个问题?例如:var1
              【解决方案7】:
              # Split-Apply-Combine: 
              do.call(
                cbind, 
                Map(
                  function(x, y){
                  replace(
                    x,
                    x == y$oldvalue,
                    y$newvalue
                  )
                },
                  split.default(
                    df,
                    seq_len(
                      ncol(
                        df
                      )
                    )
                  ),
                  split(
                    cw, 
                    seq_len(
                      nrow(
                        cw
                      )
                    )
                  )
                )
              )
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2021-02-17
                • 1970-01-01
                • 1970-01-01
                • 2020-09-02
                • 2021-11-22
                • 2021-12-27
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多