【问题标题】:fast way to create a date based lookup R创建基于日期的查找 R 的快速方法
【发布时间】:2019-12-10 23:13:48
【问题描述】:

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

我有另一个数据集,它来自支持系统,它记录了用户 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)
#

【问题讨论】:

  • 使用data.table non-equi join ...
  • 不是连接问题。这是一个查找问题。
  • 您通过连接解决了查找问题...
  • 这里的查找是一个范围,而不是一个可以被“合并”使用的明确值。我真的看不出,在这种情况下如何应用联接。 @Zeiram 提供了一个可以正常工作的答案,但不适用于 5M 行的数据集。该问题类似于 IP 范围内的 IP 查找。

标签: r date datatable grouping lookup


【解决方案1】:

您要做的操作称为“加入”,因此根据“加入”的方向和完成情况,有一些选项。

这是一个简单的例子:

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_join来自dplyrpackage 只是在查找表(df2)中查找相关值,然后根据“键”(by =在这种情况下为“ID”)。

还有其他操作可以详细说明加入的条款,但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”的问题,请参考: Left_join error cannot allocate vector of size

【讨论】:

  • 感谢解答,但是join(或merge,或left_join)并不能解决问题。我的问题是没有加入两个数据框(数据表)。在第二帧中,有许多条目与第一帧的日期周期相匹配。问题是为第二帧的每个条目获取正确的计数器。第二帧聚合后会被合并。
  • @maop joing 正在执行查找,请参阅我的示例。左表根据提供的键从查找/右表中“查找”要添加的右值。如果不是查找问题,你还想做什么?你能像我一样提供一个简单的输入/输出示例吗?
  • 示例数据框在我的代码中。在这种情况下,密钥是不够的。您应该通过检查第二个表中的日期对应的开始-结束日期期间来找到每个 id 和日期,它对应于哪个计数器。
  • 例如 id1 的会员期为 2018-02-08 到 2019-02-17,这是 id1 的第三个会员期,因此计数器为 3。ID1 在另一个数据框中有两张票,一个是从 2018-03-15 开始的,另一个是从 2019-05-16 开始的。问题是在第二帧中为 2018 年 3 月 15 日的票分配了一个计数器为 3。此日期将对应于另一个 ID 的另一个时期。对于每个 ID 和日期,都应该进行此查找。
  • @maop 我假设会员期限因人而异,不能作为组轻松添加到第二帧?查找/加入可以作用于两个键,所以你真正的问题只是创建第二个键,对吗?也许您可以朝那个方向稍微编辑您的问题。我也看不到任何模拟数据,所以很难改进我的答案。
猜你喜欢
  • 1970-01-01
  • 2010-12-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-11
  • 2014-09-04
相关资源
最近更新 更多