合并R中的多个变量

时间:2017-11-13 18:26:20

标签: r dataframe

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

例如:我有这个数据帧,并且有三个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))

6 个答案:

答案 0 :(得分:3)

您可以使用coalesce中的dplyr

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将每个名称解析为符号,然后拼接(!!!){{1}中的符号(来自@hadley的建议):

coalesce

如果您有大量的 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行,在这种情况下,您可以创建一个函数输出一个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 numeric类列,但不适用于character。在使用此方法之前,应首先将factor列转换为字符。

数据:

factor

答案 1 :(得分:1)

您也可以通过gatherspreadtidyrdplyr进行此操作。比@ useR&#39的解决方案简洁,但如果你需要进行任何中间操作,它可能会很有用。

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

答案 2 :(得分:1)

基地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)
          )

答案 3 :(得分:0)

当你可以使用已经提到的合并函数时,这将是有效的,但不是一个非常优雅的解决方案:

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),""))))

答案 4 :(得分:0)

另一种类似于@userR的解决方案,但不是单独创建每个列,而是创建一个一次性评估的表达式列表。它可能仍然遭受同样的“不要将数据帧拼接成注释中提到的!!!”错误,因为它使用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

答案 5 :(得分:0)

为了完整起见,这里还有一个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