2012-12-14 79 views
4

我有以下三个dataframes:合并的数据帧,并结合列到一个

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

是否有更通用和更优雅的方法来解决此问题?

回答

5

这里另一种可能的方法,如果我明白你最终是什么。 (不清楚“组”列中的数字值是什么,所以我不确定这正是您要查找的内容。)

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

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()可以将数据重新整形为长整型。这一事实as.numeric()将强制字符NA,并使用na.omit()NA值删除所有行的

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> 

利用。

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值等栏目,例如 - 但它可能有助于引导您迈向解决您的问题。

+0

谢谢,这个作品!我习惯了'reshape'软件包,以至于我真的很惊讶你能用'R'实现的功能。还要感谢'as.numeric()'部分的解释。 – AnjaM

+0

不错的使用减少 – zach

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 
+0

我喜欢你的'尾巴'这里。我宁愿使用'Reduce'(就像在我的答案中)一样,不得不加载一个包来进行合并。 – A5C1D2H2I1M1N2O1R2T1

+0

太好了,谢谢!我真的很喜欢使用'tail'的方法,并感谢如何以正确的方式使用'merge_recurse'。 – AnjaM

+0

merge_recurse中的一个错误会影响忽略所有参数,除了合并两个数据框的简单情况之外。所以你的例子恰好没有'all.x = TRUE'参数就能正常工作。 –