r语言 - 如何根据多列查找查找数据帧中最近的行?



>假设我有以下数据帧,其中包含数据 (v( 和一个查找数据帧 (l(:

v <- data.frame(d = c(as.Date('2019-01-01'), as.Date('2019-01-05'), as.Date('2019-01-30'), as.Date('2019-02-02')), kind=c('a', 'b', 'c', 'a'), v1=c(1,2,3,4))
v
d kind v1
1 2019-01-01    a  1
2 2019-01-05    b  2
3 2019-01-30    c  3
4 2019-02-02    a  4
l <- data.frame(d = c(as.Date('2019-01-01'), as.Date('2019-01-04'), as.Date('2019-02-01')), kind=c('a','b','a'), l1=c(10,20,30))
l
d kind l1
1 2019-01-01    a 10
2 2019-01-04    b 20
3 2019-02-01    a 30

我想使用下列找到l数据帧中对应于 v 中每一行的最接近的行:c("d", "kind").列kind需要完全匹配,也许在d上使用findInterval(...)

我希望我的结果是:

d kind v1 l1
1 2019-01-01    a  1 10
2 2019-01-05    b  2 20
3 2019-01-30    c  3 NA
4 2019-02-02    a  4 30

注意:我更喜欢 base-R 实现,但它会是 有趣地看到其他人

我尝试了findInterval(...)但我不知道如何让它与多列一起使用

这是仅在base-R中的镜头。(我确实相信data.table会做得更优雅,但我感谢您对引入其他软件包的厌恶。

kind将每个帧拆分为帧列表:

v_spl <- split(v, v$kind)
l_spl <- split(l, l$kind)
str(v_spl)
# List of 3
#  $ a:'data.frame':    2 obs. of  3 variables:
#   ..$ d   : Date[1:2], format: "2019-01-01" "2019-02-02"
#   ..$ kind: Factor w/ 3 levels "a","b","c": 1 1
#   ..$ v1  : num [1:2] 1 4
#  $ b:'data.frame':    1 obs. of  3 variables:
#   ..$ d   : Date[1:1], format: "2019-01-05"
#   ..$ kind: Factor w/ 3 levels "a","b","c": 2
#   ..$ v1  : num 2
#  $ c:'data.frame':    1 obs. of  3 variables:
#   ..$ d   : Date[1:1], format: "2019-01-30"
#   ..$ kind: Factor w/ 3 levels "a","b","c": 3
#   ..$ v1  : num 3

现在我们确定两者之间共同的独特kind,无需尝试加入所有内容:

### this has the 'kind' in common
(nms <- intersect(names(v_spl), names(l_spl)))
# [1] "a" "b"
### this has the 'kind' we have to bring back in later
(miss_nms <- setdiff(names(v_spl), nms))
# [1] "c"

对于公共kind,执行间隔连接:

joined <- Map(
v_spl[nms], l_spl[nms],
f = function(v0, l0) {
ind <- findInterval(v0$d, l0$d)
ind[ ind < 1 ] <- NA
v0$l1 <- l0$l1[ind]
v0
})

最终,我们将把事情重新rbind在一起,但miss_nms中的那些将没有新的列。这是一种使用适当的NA值精确捕获新列的一行的通用方法:

emptycols <- joined[[1]][, setdiff(colnames(joined[[1]]), colnames(v)),drop=FALSE][1,,drop=FALSE][NA,,drop=FALSE]
emptycols
#    l1
# NA NA

并将该列添加到尚未找到的框架中:

unjoined <- lapply(v_spl[miss_nms], cbind, emptycols)
unjoined
# $c
#            d kind v1 l1
# 3 2019-01-30    c  3 NA

最后将所有内容放回一帧中:

do.call(rbind, c(joined, unjoined))
#              d kind v1 l1
# a.1 2019-01-01    a  1 10
# a.4 2019-02-02    a  4 30
# b   2019-01-05    b  2 20
# c   2019-01-30    c  3 NA

如果你想要一个完全匹配,你会去:

vl <- merge(v, l, by = c("d","kind"))

出于您的目的,您可以将 d 转换为年、月或日的其他变量,并使用合并

最新更新