【问题标题】:Merge multiple variables in R合并R中的多个变量
【发布时间】:2017-11-13 18:26:19
【问题描述】:

我有一个数据集,相同的变量包含在每个主题的不同列中。我想将它们合并到相同的列。

例如:,我有这个数据框,并且有三个 DV,但它们针对不同的主题位于不同的列(A、B、C)中。

data.frame(ID = c(1,2,3), DV1_A=c(1,NA,NA), DV1_B= c(NA,4,NA), DV1_C = c(NA,NA,5), DV2_A=c(3,NA,NA), DV2_B=c(NA,3,NA), DV2_C=c(NA,NA,5), FACT = c("A","B","C"))

如何将它们合并为两列?所以结果是:

data.frame(ID = c(1,2,3), DV1_A=c(1,NA,NA), DV1_B= c(NA,4,NA), DV1_C = c(NA,NA,5), DV2_A=c(3,NA,NA), DV2_B=c(NA,3,NA), DV2_C=c(NA,NA,5), FACT = c("A","B","C"), DV_1 = c(1,4,5), DV_2 = c(3,3,5))

【问题讨论】:

    标签: r dataframe


    【解决方案1】:

    您可以从dplyr 使用coalesce

    library(dplyr)
    
    df %>%
      mutate(DV_1 = coalesce(DV1_A, DV1_B, DV1_C),
             DV_2 = coalesce(DV2_A, DV2_B, DV2_C))
    

    如果您有很多 DV 要组合,您可能不想键入所有列名。在这种情况下,您可以先grep 每个DV 的列名,用rlang::syms 将每个名称解析为符号,然后拼接(!!!coalesce 中的符号(来自@hadley 的建议):

    library(rlang)
    var_quo1 = syms(grep("DV1", names(df), value = TRUE))
    var_quo2 = syms(grep("DV2", names(df), value = TRUE))
    
    df %>%
      mutate(DV_1 = coalesce(!!! var_quo1),
             DV_2 = coalesce(!!! var_quo2))
    

    如果相反,您有大量 DV's,您甚至可能不想输入所有 coalesce 行,在这种情况下,您可以创建一个输出一个的函数DV 列给定一个输入数字和lapply + bind_col 一起:

    DV_combine = function(num_DVs){
    
      DV_name = sym(paste0("DV", num_DVs))
      DV_syms = syms(grep(paste0("DV", num_DVs), names(df), value = TRUE))
    
      df %>%
        transmute(!!DV_name := coalesce(!!! DV_syms))
    }
    
    bind_cols(df, lapply(1:2, DV_combine))
    

    结果:

      ID DV1_A DV1_B DV1_C DV2_A DV2_B DV2_C FACT DV_1 DV_2
    1  1     1    NA    NA     3    NA    NA    A    1    3
    2  2    NA     4    NA    NA     3    NA    B    4    3
    3  3    NA    NA     5    NA    NA     5    C    5    5
    

    注意:

    此方法适用于numericcharacter 类列,但不适用于factor。在使用此方法之前,应首先将factor 列转换为字符。

    数据:

    df = structure(list(ID = c(1, 2, 3), DV1_A = c(1, NA, NA), DV1_B = c(NA, 
    4, NA), DV1_C = c(NA, NA, 5), DV2_A = c(3, NA, NA), DV2_B = c(NA, 
    3, NA), DV2_C = c(NA, NA, 5), FACT = structure(1:3, .Label = c("A", 
    "B", "C"), class = "factor")), .Names = c("ID", "DV1_A", "DV1_B", 
    "DV1_C", "DV2_A", "DV2_B", "DV2_C", "FACT"), row.names = c(NA, 
    -3L), class = "data.frame")
    

    【讨论】:

    • 一般来说,我建议不要将数据帧拼接到带有!!! 的调用中。最好在变量名中拼接
    • 感谢@hadley 的建议,但您的意思是像greping colnames,解析为quosures,然后与!!! 拼接?我试图利用starts_with,但是是的,我同意拼接整个数据帧可能不是一个好主意。
    • 是的,没错。主要挑战是select() 语法非常好,以至于您想在采用... 的矢量化函数中使用它,但目前没有很好的方法。
    【解决方案2】:

    您也可以通过gatherspread 以及tidyrdplyr 执行此操作。不如@user 的解决方案简洁,但如果您需要进行任何中间操作,可能会很有用。

    library(dplyr)
    library(tidyr)
    
    df %>% 
      gather(variable, value, -ID, -FACT, na.rm = TRUE) %>% 
      mutate(variable = gsub("\\_[A-Z]", "", variable)) %>% 
      spread(variable, value) %>% 
      left_join(df)
    
      ID FACT DV1 DV2 DV1_A DV1_B DV1_C DV2_A DV2_B DV2_C
    1  1    A   1   3     1    NA    NA     3    NA    NA
    2  2    B   4   3    NA     4    NA    NA     3    NA
    3  3    C   5   5    NA    NA     5    NA    NA     5
    

    【讨论】:

      【解决方案3】:

      基础transform 会这样做:

      d <- transform(d, 
                     DV1 = rowSums(d[c("DV1_A", "DV1_B", "DV1_C")], na.rm=T),
                     DV2 = rowSums(d[c("DV2_A", "DV2_B", "DV2_C")], na.rm=T)
                )
      

      【讨论】:

        【解决方案4】:

        当您可以使用已经提到的 coalesce 函数时,这会起作用,但不是一个非常优雅的解决方案:

        library(dplyr)
        test <- df %>% group_by(ID) %>% summarise(DV1 = ifelse(!is.na(DV1_A),paste(DV1_A),ifelse(!is.na(DV1_B),paste(DV1_B),ifelse(!is.na(DV1_C),paste(DV1_C),""))), DV2 = ifelse(!is.na(DV2_A),paste(DV2_A),ifelse(!is.na(DV2_B),paste(DV2_B),ifelse(!is.na(DV2_C),paste(DV2_C),""))))
        

        【讨论】:

          【解决方案5】:

          另一个类似于@userR 的解决方案,但不是单独创建每一列,而是创建一个表达式列表,这些表达式可以一次全部计算。它可能仍然遭受与 cmets 中提到的相同的“不要将数据帧拼接到带有 !!! 的调用中”的错误,因为它使用了 select(.),但我想我还是会发布。


          library(rlang)
          library(dplyr)
          
          df <- data.frame(ID = c(1,2,3), DV1_A=c(1,NA,NA), 
                           DV1_B= c(NA,4,NA), DV1_C = c(NA,NA,5), 
                           DV2_A=c(3,NA,NA), DV2_B=c(NA,3,NA), 
                           DV2_C=c(NA,NA,5), FACT = c("A","B","C"))
          
          create_DV <- function(num) {
            DV_name <- sym(paste0("DV_", num))
            DV_char <- paste0("DV", num)
          
            expr(!! DV_name := select(., contains(!! DV_char)) %>% rowSums(na.rm = TRUE))
          }
          
          DV_expr_list <- c(1,2) %>% 
            lapply(create_DV)
          
          df %>%
            mutate(
              !!! DV_expr_list
            )
          #>   ID DV1_A DV1_B DV1_C DV2_A DV2_B DV2_C FACT DV_1 DV_2
          #> 1  1     1    NA    NA     3    NA    NA    A    1    3
          #> 2  2    NA     4    NA    NA     3    NA    B    4    3
          #> 3  3    NA    NA     5    NA    NA     5    C    5    5
          

          【讨论】:

            【解决方案6】:

            为了完整起见,这里还有一个data.table 解决方案,使用melt() 同时重塑两个度量变量:

            library(data.table)
            cols <- c("DV1", "DV2")
            melt(setDT(DF), measure.vars = patterns(cols), value.name = cols, na.rm = TRUE)[
              , -"variable"]
            
               ID FACT DV1 DV2
            1:  1    A   1   3
            2:  2    B   4   3
            3:  3    C   5   5
            

            现在,按照 OP 的要求,这六列已合并为两列。

            但是,OP 提供了一个带有预期结果的 data.frame,其中新列附加到现有列。这可以通过将上述结果与原始数据框连接来实现:

             setDT(DF)[melt(DF, measure.vars = patterns(cols), value.name = cols, na.rm = TRUE)[
              , -"variable"], on = .(ID, FACT)]
            
               ID DV1_A DV1_B DV1_C DV2_A DV2_B DV2_C FACT DV1 DV2
            1:  1     1    NA    NA     3    NA    NA    A   1   3
            2:  2    NA     4    NA    NA     3    NA    B   4   3
            3:  3    NA    NA     5    NA    NA     5    C   5   5
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2018-09-12
              • 2021-03-06
              • 1970-01-01
              • 2018-11-29
              • 1970-01-01
              • 1970-01-01
              • 2021-10-10
              • 2022-07-11
              相关资源
              最近更新 更多