合并数据框并将列组合成一个

时间:2012-12-14 14:56:18

标签: r

我有以下三个数据帧:

df1 <- data.frame(name=c("John", "Anne", "Christine", "Andy"),
                  age=c(31, 26, 54, 48),
                  height=c(180, 175, 160, 168),
                  group=c("Student",3,5,"Employer"), stringsAsFactors=FALSE)

df2 <- data.frame(name=c("Anne", "Christine"),
                  age=c(26, 54),
                  height=c(175, 160),
                  group=c(3,5),
                  group2=c("Teacher",6), stringsAsFactors=FALSE)

df2 <- data.frame(name=c("Christine"),
                  age=c(54),
                  height=c(160),
                  group=c(5),
                  group2=c(6),
                  group3=c("Scientist"), stringsAsFactors=FALSE)

我想将它们组合起来,以便得到以下结果:

df.all <- data.frame(name=c("John", "Anne", "Christine", "Andy"),
                     age=c(31, 26, 54, 48),
                     height=c(180, 175, 160, 168),
                     group=c("Student", "Teacher", "Scientist", "Employer"))

目前我正是这样做的:

df.all <- merge(merge(df1[,c(1,4)], df2[,c(1,5)], all=TRUE, by="name"),
                df3[,c(1,6)], all=TRUE, by="name")
row.ind <- which(df.all$group %in% c(6,5))
df.all[row.ind, c("group")] <- df.all[row.ind, c("group2")]
row.ind2 <- which(df.all$group2 %in% c(6))
df.all[row.ind2, c("group")] <- df.all[row.ind2, c("group3")]

这不是一般性的,而且非常混乱。也许有一种方法可以使用merge_allmerge_recurse进行合并步骤(特别是因为可能有两个以上的数据框要合并),但我还没弄清楚如何。这两个不能产生正确的结果:

df.all <- merge_all(list(df1, df2, df3))
df.all <- merge_recurse(list(df1, df2, df3), by=c("name"))

是否有更通用,更优雅的方法来解决这个问题?

2 个答案:

答案 0 :(得分:5)

如果我明白你最终会追求什么,这是另一种可行的方法。 (目前尚不清楚“组”列中的数值是什么,所以我不确定这正是您正在寻找的。)

使用Reduce()合并您的多个data.frame

temp <- Reduce(function(x, y) merge(x, y, all=TRUE), list(df1, df2, df3))
names(temp)[4] <- "group1" # Rename "group" to "group1" for reshaping 
temp
#        name age height   group1  group2    group3
# 1      Andy  48    168 Employer    <NA>      <NA>
# 2      Anne  26    175        3 Teacher      <NA>
# 3 Christine  54    160        5       6 Scientist
# 4      John  31    180  Student    <NA>      <NA>

使用reshape()从长到长重塑您的数据。

df.all <- reshape(temp, direction = "long", idvar="name", varying=4:6, sep="")
df.all
#                  name age height time     group
# Andy.1           Andy  48    168    1  Employer
# Anne.1           Anne  26    175    1         3
# Christine.1 Christine  54    160    1         5
# John.1           John  31    180    1   Student
# Andy.2           Andy  48    168    2      <NA>
# Anne.2           Anne  26    175    2   Teacher
# Christine.2 Christine  54    160    2         6
# John.2           John  31    180    2      <NA>
# Andy.3           Andy  48    168    3      <NA>
# Anne.3           Anne  26    175    3      <NA>
# Christine.3 Christine  54    160    3 Scientist
# John.3           John  31    180    3      <NA>

利用as.numeric()将字符强制转换为NA这一事实,并使用na.omit()删除所有NA个值的行。

na.omit(df.all[is.na(as.numeric(df.all$group)), ])
#                  name age height time     group
# Andy.1           Andy  48    168    1  Employer
# John.1           John  31    180    1   Student
# Anne.2           Anne  26    175    2   Teacher
# Christine.3 Christine  54    160    3 Scientist

同样,这可能会过度概括您的问题 - 例如,其他列中可能存在NA值 - 但它可能有助于指导您解决问题。

答案 1 :(得分:4)

第一步是将merge_recurseall.x = TRUE

一起使用
library(reshape)
merge.all <- merge_recurse(list(df1, df2, df3), all.x = TRUE)
#        name age height    group  group2    group3
# 1      Anne  26    175        3 Teacher      <NA>
# 2 Christine  54    160        5       6 Scientist
# 3      John  31    180  Student    <NA>      <NA>
# 4      Andy  48    168 Employer    <NA>      <NA>

然后,您可以使用apply从所有“组”列中获取最后一个非NA组:

group.cols <- grep("group", colnames(merge.all))
merge.all <- data.frame(merge.all[-group.cols],
                        group = apply(merge.all[group.cols], 1,
                                      function(x)tail(na.omit(x), 1)))
#        name age height     group
# 1      Anne  26    175   Teacher
# 2 Christine  54    160 Scientist
# 3      John  31    180   Student
# 4      Andy  48    168  Employer