我有一个数据集,使得每个主题的差异列中包含相同的变量。我想将它们合并到相同的列。
例如:我有这个数据帧,并且有三个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))
答案 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)
您也可以通过gather
和spread
与tidyr
和dplyr
进行此操作。比@ 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