[英]Merge data frames whilst summing common columns in R
不同之处在于,他们知道列会产生冲突,而我需要一种通用方法,它不会事先知道哪些列发生冲突。
例:
TABLE1
Date Time ColumnA ColumnB
01/01/2013 08:00 10 30
01/01/2013 08:30 15 25
01/01/2013 09:00 20 20
02/01/2013 08:00 25 15
02/01/2013 08:30 30 10
02/01/2013 09:00 35 5
TABLE2
Date ColumnA ColumnB ColumnC
01/01/2013 100 300 1
02/01/2013 200 400 2
表2仅包含日期,因此适用于表A中与日期无关的所有字段。
我希望合并将冲突的列加总为1.结果应如下所示:
TABLE3
Date Time ColumnA ColumnB ColumnC
01/01/2013 08:00 110 330 1
01/01/2013 08:30 115 325 1
01/01/2013 09:00 120 320 1
02/01/2013 08:00 225 415 2
02/01/2013 08:30 230 410 2
02/01/2013 09:00 235 405 2
目前,我的标准合并只会创建“ColumnA.x”,“ColumnA.y”,“ColumnB.x”,“ColumnB.y”的重复列。
任何帮助深表感谢
如果我理解正确,您需要一种灵活的方法,除了要合并的列和要保留的列之外,不需要知道每个表中存在哪些列。 这可能不是最优雅的解决方案,但这里有一个示例功能,以满足您的确切需求:
merge_Sum <- function(.df1, .df2, .id_Columns, .match_Columns){
merged_Columns <- unique(c(names(.df1),names(.df2)))
merged_df1 <- data.frame(matrix(nrow=nrow(.df1), ncol=length(merged_Columns)))
names(merged_df1) <- merged_Columns
for (column in merged_Columns){
if(column %in% .id_Columns | !column %in% names(.df2)){
merged_df1[, column] <- .df1[, column]
} else if (!column %in% names(.df1)){
merged_df1[, column] <- .df2[match(.df1[, .match_Columns],.df2[, .match_Columns]), column]
} else {
df1_Values=.df1[, column]
df2_Values=.df2[match(.df1[, .match_Columns],.df2[, .match_Columns]), column]
df2_Values[is.na(df2_Values)] <- 0
merged_df1[, column] <- df1_Values + df2_Values
}
}
return(merged_df1)
}
此函数假定您有一个表'.df1',它是一个排序主,并且您希望合并第二个表'.df2'中的数据,该表具有与'.df1'中的一个或多个行匹配的行。 要保留在主表'.df1'中的列被接受为数组'.id_Columns',并且提供用于合并这两个表的匹配的列被接受为数组'.match_Columns'
对于您的示例,它将像这样工作:
merge_Sum(table1, table2, c("Date","Time"), "Date")
# Date Time ColumnA ColumnB ColumnC
# 1 01/01/2013 08:00 110 330 1
# 2 01/01/2013 08:30 115 325 1
# 3 01/01/2013 09:00 120 320 1
# 4 02/01/2013 08:00 225 415 2
# 5 02/01/2013 08:30 230 410 2
# 6 02/01/2013 09:00 235 405 2
在简单语言中,此函数首先查找唯一列的总数,并以主表“.df1”的形状创建一个空数据框,以便稍后保存合并数据。 然后,对于'.id_Columns',数据从'.df1'复制到新的合并数据帧中。 对于其他列,“。df1”中存在的任何数据都会添加到“.df2”中的任何现有数据中,其中“.df2”中的行根据“.match_Columns”进行匹配
可能有一些类似的程序包,但大多数需要知道所有现有的列以及如何处理它们。 正如我之前所说,这不是最优雅的解决方案,但它灵活而准确。
更新 :原始函数假定table1和table2之间存在多对一关系,并且OP也请求允许多对多关系。 代码已经更新,效率稍低但100%更灵活的逻辑。
一个data.table
解决方案:
dt1 <- data.table(read.table(header=T, text="Date Time ColumnA ColumnB
01/01/2013 08:00 10 30
01/01/2013 08:30 15 25
01/01/2013 09:00 20 20
02/01/2013 08:00 25 15
02/01/2013 08:30 30 10
02/01/2013 09:00 35 5"))
dt2 <- data.table(read.table(header=T, text="Date ColumnA ColumnB ColumnC
01/01/2013 100 300 1
02/01/2013 200 400 2"))
setkey(dt1, "Date")
setkey(dt2, "Date")
# Note: The ColumnC assignment has to be come before the summing operations
# Else it gives out error (see below)
dt1[dt2, `:=`(ColumnC = i.ColumnC, ColumnA = ColumnA + i.ColumnA,
ColumnB = ColumnB + i.ColumnB)]
# Date Time ColumnA ColumnB ColumnC
# 1: 01/01/2013 08:00 110 330 1
# 2: 01/01/2013 08:30 115 325 1
# 3: 01/01/2013 09:00 120 320 1
# 4: 02/01/2013 08:00 225 415 2
# 5: 02/01/2013 08:30 230 410 2
# 6: 02/01/2013 09:00 235 405 2
我不确定为什么在ColumnC
放置ColumnC
赋值会抛出此错误。 也许MatthewDowle可以解释这个错误的原因。
dt1[dt2, `:=`(ColumnA = ColumnA + i.ColumnA, ColumnB = ColumnB + i.ColumnB,
ColumnC = i.ColumnC)]
Error in `[.data.table`(dt1, dt2, `:=`(ColumnA = ColumnA + i.ColumnA, :
Value of SET_STRING_ELT() must be a 'CHARSXP' not a 'NULL'
从v1.8.9更新:
o将添加new和更新现有列混合为一个
:=
()by group; 即
DT[,
:=(existingCol=...,newCol=...), by=...]
现在无错误或段错误,#2778和#2528。 非常感谢Arun通过可重复的示例进行报告。 测试补充说。
我编写了包safejoin ,它非常简洁地解决了这个问题
#devtools::install_github("moodymudskipper/safejoin")
library(safejoin)
safe_full_join(df1,df2, by = "Date", conflict = `+`)
# Date Time ColumnA ColumnB ColumnC
# 1 01/01/2013 08:00 110 330 1
# 2 01/01/2013 08:30 115 325 1
# 3 01/01/2013 09:00 120 320 1
# 4 02/01/2013 08:00 225 415 2
# 5 02/01/2013 08:30 230 410 2
# 6 02/01/2013 09:00 235 405 2
如果发生冲突,函数+
将用于成对的冲突列
数据
df1 <- read.table(header=T, text="Date Time ColumnA ColumnB
01/01/2013 08:00 10 30
01/01/2013 08:30 15 25
01/01/2013 09:00 20 20
02/01/2013 08:00 25 15
02/01/2013 08:30 30 10
02/01/2013 09:00 35 5")
df2 <- read.table(header=T, text="Date ColumnA ColumnB ColumnC
01/01/2013 100 300 1
02/01/2013 200 400 2")
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.