4

我有以下三个数据框:

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

有没有更通用和优雅的方法来解决这个问题?

4

2 回答 2

5

如果我了解您最终的目标,这是另一种可能的方法。(不清楚“组”列中的数值是什么,所以我不确定这正是你要找的。)

用于Reduce()合并您的多个data.frames。

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 值 - 但它可能有助于引导您找到问题的解决方案。

于 2012-12-14T18:26:28.520 回答
4

第一步是使用merge_recursewith all.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
于 2012-12-14T15:18:52.927 回答