创建基于日期的查找 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_join
从dplyr
包中简单地在查找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"的问题请参考:
我有一个非常大的数据集,其中包含用户及其成员资格的开始和结束日期。每个会员期都有一个条目。
我有另一个数据集,它来自支持系统,它记录了用户 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_join
从dplyr
包中简单地在查找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"的问题请参考: