基于日期时间条件合并ID不匹配的两个数据集的方法
嘿,我来帮你搞定这个合并难题!首先我注意到你给的示例数据里,数据集b目前没有包含date列,但你明确说两个数据集的日期时间是一致的——我先假设b其实也有对应的时间字段(如果实际情况是b的行序和a严格对齐、时间完全匹配,后面也会补充这种特殊场景的处理方式)。
核心思路
既然ID没法作为合并的依据,那咱们就换个思路,用日期时间作为核心合并键!如果还有其他共同的标识列(比如你数据里的X),最好也一起加入合并键,避免同时间有多条记录时出现不必要的笛卡尔积。不过有个关键前提:必须把字符串格式的日期转换成R能识别的日期时间类型(比如POSIXct),不然很容易因为空格、格式差异导致匹配失败(比如你a里第二个date末尾多了个空格,直接用字符串合并就会匹配不上)。
步骤1:整理并标准化你的数据
先把你给的示例数据修正成更规范的R格式(cbind()会把所有列转成字符型,直接用data.frame()创建更稳妥),同时给b补上对应的date列:
# 处理数据集a:转换date为标准日期时间类型,自动去除末尾空格 a <- data.frame( X = c("A","B"), S = c("p", "A"), ID = c(1234,2456), date = as.POSIXct(c("23/1/2017 9:00","23/1/2017 9:00 "), format = "%d/%m/%Y %H:%M") ) # 处理数据集b:补充date列,同样转成标准类型 b <- data.frame( X = c("A","B"), C = c(10, 200), ID = c(1234,1234), date = as.POSIXct(c("23/1/2017 9:00","23/1/2017 9:00"), format = "%d/%m/%Y %H:%M") )
步骤2:基于日期时间+X列合并
因为你的示例里同一时间有两条不同的记录(X=A和X=B),只靠date合并会产生重复匹配,所以咱们同时用X和date作为合并键,这样就能精准匹配每一条记录了。
方法1:用基础R的merge()函数
这是最经典的合并方式,兼容性拉满:
# 内连接:只保留两边都能匹配上的记录 D <- merge(a, b, by = c("X", "date"), all = FALSE) # 如果需要保留a里的所有记录(哪怕b里没有对应匹配),用左连接: # D <- merge(a, b, by = c("X", "date"), all.x = TRUE) # 要是需要保留两边所有记录,用全连接: # D <- merge(a, b, by = c("X", "date"), all = TRUE)
方法2:用dplyr包(更简洁的tidy风格)
如果你平时用tidyverse工具链,dplyr的连接函数语法更直观:
library(dplyr) # 内连接 D <- inner_join(a, b, by = c("X", "date")) # 左连接 # D <- left_join(a, b, by = c("X", "date"))
特殊场景:如果b没有date列,但行序严格对应
要是b确实没有date字段,但你能100%保证b的每一行和a的行是一一对应的(第一行对应第一行,第二行对应第二行),那直接用cbind()就行,但要注意去掉重复的列(比如两个数据集都有X和ID):
# 去掉b里和a重复的列,再合并 D <- cbind(a, b[, !names(b) %in% c("X", "ID")])
合并后的结果示例
用内连接得到的D大概是这样的:
| X | S | ID.x | date | C | ID.y |
|---|---|---|---|---|---|
| A | p | 1234 | 2017-01-23 09:00:00 | 10 | 1234 |
| B | A | 2456 | 2017-01-23 09:00:00 | 200 | 1234 |
这里ID.x是a里的ID,ID.y是b里的ID,你可以用rename()修改成更清晰的名字:
# 基础R写法 colnames(D)[colnames(D) == "ID.x"] <- "ID_a" colnames(D)[colnames(D) == "ID.y"] <- "ID_b" # dplyr写法 D <- D %>% rename(ID_a = ID.x, ID_b = ID.y)
内容的提问来源于stack exchange,提问作者Raja Muhammad

