首页 > 解决方案 > R - 删除 data.table 滚动连接中所有不匹配行的最有效方法(而不是半连接的两步过程)

问题描述

目前通过解决方法解决此问题,但我想知道是否有更有效的方法。

有关示例性数据,请参见下文:

library(data.table)
library(anytime)
library(tidyverse)
library(dplyr)
library(batchtools)

# Lookup table 
Date <- c("1990-03-31", "1990-06-30", "1990-09-30", "1990-12-31",
          "1991-03-31", "1991-06-30", "1991-09-30", "1991-12-31")
period <- c(1:8)
metric_1 <- rep(c(2000, 3500, 4000, 100000), 2)
metric_2 <- rep(c(200, 350, 400, 10000), 2)
id <- 22

dt <- setDT(data.frame(Date, period, id, metric_1, metric_2))


# Fill and match table 2
Date_2 <- c("1990-08-30", "1990-02-28", "1991-07-31", "1991-09-30", "1991-10-31")
random <- c(10:14)
id_2 <- c(22,33,57,73,999)

dt_fill <- setDT(data.frame(EXCL_DATE, random, id_2))


# Convert date columns to type date
dt[ , Date := anydate(Date)]
dt_fill[ , Date_2 := anydate(Date_2)]

现在进行数据争论。dt我想从(又名查找表)中获取最新的先前数据到dt_fill. 我用这样一个简单的 1 线滚动连接来做到这一点。

# Rolling join
dt_res <- dt[dt_fill, on = .(id = id_2, Date = Date_2), roll = TRUE] 
# if not all id_2 present in id column in table 1, we get rows with NA
# I want to only retain the rows with id's that were originally in the lookup table

然后我以一堆填充了NAs我想删除的新添加列的行结束。我用semi-join. 我发现过时的解决方案很难理解,并解决了batchtools::sjoin()本质上也是单线的功能。

dt_final <- sjoin(dt_res, dt, by = "id")

有没有比先进行滚动连接然后与原始数据集进行半连接更有效的方法来完成滚动连接的干净输出结果。对于非常长的数据集,它也不是很快。谢谢!

标签: rdata.table

解决方案


从本质上讲,我发现有两种方法都是可行的解决方案。

解决方案 1

首先,由 lil_barnacle 提出的是一个优雅的单行代码,如下所示:

# Rolling join with nomtach-argument set to 0
dt_res <- dt[dt_fill, on = .(id = id_2, Date = Date_2), roll = TRUE, nomatch=0]

原始方法

像这样添加nomatch参数并将其设置为 0 nomatch = 0,相当于先进行滚动连接,然后再进行半连接。

# Rolling join without specified nomatch argument 
dt_res <- dt[dt_fill, on = .(id = id_2, Date = Date_2), roll = TRUE] 

# Semi-join required
dt_final <- sjoin(dt_res, dt, by = "id")

解决方案 2

其次,我想出的解决方案是在滚动连接之前通过“连接变量”过滤来“对齐”两个数据集,如下所示:

# Aligning data sets by filtering accd. to joined 'variable'
dt_fill <- dt_fill[id_2 %in% dt[ , unique(id)]]

# Rolling join without need to specify nomatch argument 
dt_res <- dt[dt_fill, on = .(id = id_2, Date = Date_2), roll = TRUE] 

推荐阅读