创建基于日期的查找 R 的快速方法

fast way to create a date based lookup R

我有一个非常大的数据集,其中包含用户及其成员资格的开始和结束日期。每个会员期都有一个条目。

我有另一个数据集,它来自支持系统,它记录了用户 ID 以及每个系统使用的日期。这个数据集更大,因为每次使用都有一条记录。

我需要根据每个用户和会员期限汇总第二个并与第一个合并。

我尝试了一个用于 for 循环的函数,但是对于一个非常大的数据集(她我们正在谈论几百万行)这将需要很长时间。

编辑:加入或合并将不起作用,因为此处第一帧中的每个 ID 有多个范围(在开始日期和结束日期之间)。每个范围都分配了一个编号。 (会员期限)第二个数据框有日期和 ID,问题是通过将每个 ID 和日期与第一帧中的日期范围进行比较来找到每个 ID 和日期的会员期限。

这是代码,以及模拟数据集和我最后想要实现的目标:

ids <- c(rep("id1", 5), rep("id2", 5), rep("id3", 5))
#
stdates <- c("2015-08-01", "2016-08-01", "2017-08-01", "2018-08-01", "2019-08-01",
             "2013-05-07", "2014-05-07", "2015-05-07", "2016-05-07", "2017-05-07",
             "2011-02-13", "2013-02-13", "2015-02-13", "2016-02-13", "2017-02-13")
#
endates <- c("2016-07-31", "2017-07-31", "2018-07-31", "2019-07-31", "2020-07-31",
             "2014-05-06", "2015-05-06", "2016-05-06", "2017-05-06", "2018-05-06",
             "2013-02-12", "2015-02-12", "2016-02-12", "2017-02-12", "2018-02-12")
#
# First dataset:
df <- data.table(id = ids,
                 stdate = stdates,
                 endate = endates)
#
df <- df %>%
  arrange(id, desc(endate))
#
# Add the membership period number for each user:
setDT(df)
df[, counter := rowid(id)]
#
# Second dataset:
ids2 <- sample(df$id, 1000, replace = TRUE)
dates2 <- sample(seq(Sys.Date() - 7*365, Sys.Date() - 365,  1), 1000)

#
df2 <- data.table(id = ids2,
                  dateticket = dates2)
#
# Function
counterFunc <- function(d2, d1) {
  d2$groupCounter <- NA
  for (i in 1:nrow(d2)) {
    crdate <- d2$dateticket[i]
    idtemp <- d2$id[i]
    dtemp <- d1 %>%
      filter(id == idtemp) %>%
      data.table()
    dtemp[, drcode := ifelse(crdate >= stdate & crdate <= endate, 1, 0)]
    if (length(unique(dtemp$drcode)) == 2) {
      dtempgc <- dtemp[drcode == 1]$counter
      d2$groupCounter[i] <- dtempgc
    }
    if (length(unique(dtemp$drcode)) != 2) {
      d2$groupCounter[i] <- 0
    }
    print(i)
  }
  return(d2)
}
#
# The result I want to get without a for loop:
df2gc <- counterFunc(df2, df)
#

您要执行的操作称为 "joining",因此根据 "joining" 的方向和完成情况,有一些选项。

这是一个简单的例子:

df1<-data.frame("ID"=c("1","2","3","1","2"),"First_Name"=c("A","B","C","D","E"))

df2<-data.frame("ID"=c("1","2","3"),"Last_Name"=c("Ko","Lo","To"))

left_join(df1,df2,by = "ID")

结果如下所示:

 ID First_Name Last_Name 
 1          A        Ko
 2          B        Lo
 3          C        To
 1          A        Ko
 2          B        Lo

left_joindplyr包中简单地在查找table(df2)中查找相关值并将它们添加到原始table(df1 , 左 table) 基于一个 "key" (by = "ID" in this case).

还有其他操作可以更多地指定加入的条款,但left_join应该对您的情况有所帮助。

编辑:

我现在更好地理解了你的问题。请检查这是否解决了问题:

library(tidyverse)
df %>%
  mutate(stdate = as.Date(stdate), endate = as.Date(endate)) %>%
  left_join(df2, by = "id") %>%
  mutate(check = case_when(dateticket >= stdate & dateticket <= endate ~ "TRUE", TRUE ~ "FALSE")) %>%
  filter(check == "TRUE")

编辑:

加入错误"Cannot allocate vector of size"的问题请参考: