在数据框或数据表中连接匹配的列

8

我有以下数据框:

a <- data.frame(id = 1:3, v1 = c('a', NA, NA), v2 = c(NA, 'b', 'c'))
b <- data.frame(id = 1:3, v1 = c(NA, 'B', 'C'), v2 = c("A", NA, NA))
> a
  id   v1   v2
1  1    a <NA>
2  2 <NA>    b
3  3 <NA>    c
> b
  id   v1   v2
1  1 <NA>    A
2  2    B <NA>
3  3    C <NA>

注意:在这两个表中,不存在v1或v2都已定义的id;每个id值的每列只有一个唯一的非NA值。

我想要根据"id"的匹配值合并这些数据框:

ab <- merge(a, b, by = "id")

但我也想将两列v1v2组合起来,这样数据框ab看起来就像这样:

ab <- data.frame(id = 1:3, v1 = c("a", "B", "C"), v2 = c("A", "b", "c"))

> ab
  id v1 v2
1  1  a  A
2  2  B  b
3  3  C  c

相反,我得到了这个:
> merge(a, b, by = "id")
  id v1.x v2.x v1.y v2.y
1  1    a <NA> <NA>    A
2  2 <NA>    b    B <NA>
3  3 <NA>    c    C <NA>

使用data.framedata.table的示例将非常有帮助,因此以下是上面的data.table版本:

A <- data.table(a, key = 'id')
B <- data.table(b, key = 'id')
A[B]
2个回答

8
你指定的合并类型可能无法使用merge(与数据框)进行,尽管这样说通常会被证明是错误的。你还省略了一些细节:对于每个id值的每个列中总会有一个单独的非NA值吗?如果是这样,那么这将起作用:
ab <- rbind(a,b)
> colFun <- function(x){x[which(!is.na(x))]}
> ddply(ab,.(id),function(x){colwise(colFun)(x)})
  id v1 v2
1  1  a  A
2  2  B  b
3  3  C  c

使用类似的策略也可以适用于 data.table

abDT <- data.table(ab,key = "id")
> abDT[,list(colFun(v1),colFun(v2)),by = id]
     id V1 V2
[1,]  1  a  A
[2,]  2  B  b
[3,]  3  C  c

答案是“是”,总会有“一个唯一的非NA值”;这是更清晰地陈述我在第一个代码块下的注释中试图传达的内容:“没有id,v1或v2在两个表中都被定义”。 - David LeBauer
1
+1 for colwise。我之前不知道这个函数,但它看起来很方便。 - Brandon Bertelsen
@TylerRinker 我不确定你所说的不同id是什么意思。 - joran
此外,@MatthewDowle肯定能够建议一种更流畅的方式来将colFun应用于每一列,而不需要明确列出它们。 - joran
嗨。一个习语是 DT[,lapply(.SD,colFun),by=id] - Matt Dowle
@MatthewDowle 我已经想出了 lapply(colnames(abDT), colFun) 但是留下了无名列; .SD 真是太棒了!而且速度非常快。 - David LeBauer

4
如果你的数据像上面那样简单,joran的回答可能是最简单的方法。以下是我的基本方法:
a <- data.frame(id = 1:3, v1 = c('a', NA, NA), v2 = c(NA, 'b', 'c'))
b <- data.frame(id = 1:3, v1 = c(NA, 'B', 'C'), v2 = c("A", NA, NA))

decider <- function(x, y) factor(ifelse(is.na(x), as.character(y), as.character(x)))
data.frame(mapply(a, b, FUN = decider))

如果您的数据具有不同的ID(有些重叠,有些不重叠),那么这里有一种不同的方法:

a <- data.frame(id = c(1,2,4,5), v1 = c('a', NA, "q", NA), v2 = c(NA, 'b', 'c', "e"))
b <- data.frame(id = 1:4, v1 = c(NA, "A", "C", 'B'), v2 = c("A", NA, "D", NA))

decider <- function(x, y) factor(ifelse(is.na(x), as.character(y), as.character(x)))

DF <- data.frame(mapply(a, b, FUN = decider))
DF2 <- rbind(b[!b$id %in% DF$id , ], DF)
DF2 <- DF2[order(DF2$id), ]
rownames(DF2) <- 1:nrow(DF2)

1
啊,我明白你的意思了。有些id出现在一个数据框中但另一个没有。我猜测我的一般策略在这种情况下仍然适用,假设OP的规范仍然成立,这意味着孤立的id不会有任何NA值。 - joran

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接