我有以下数据帧:
AllDays
2012-01-01
2012-01-02
2012-01-03
...
2015-08-18
Leases
StartDate EndDate
2012-01-01 2013-01-01
2012-05-07 2013-05-06
2013-09-05 2013-12-01
Run Code Online (Sandbox Code Playgroud)
我想要做的是,对于allDays数据帧中的每个日期,计算有效的租约数量.例如,如果有4个租约的开始日期<= 2015-01-01和结束日期> = 2015-01-01,那么我想在该数据帧中放置一个4.
我有以下代码
for (i in 1:nrow(leases))
{
occupied = seq(leases$StartDate[i],leases$EndDate[i],by="days")
occupied = occupied[occupied < dateOfInt]
matching = match(occupied,allDays$Date)
allDays$Occupancy[matching] = allDays$Occupancy[matching] + 1
}
Run Code Online (Sandbox Code Playgroud)
这是有效的,但由于我有大约5000个租约,它需要大约1.1秒.有没有人有更有效的方法需要更少的计算时间?利息日仅为当前日期,仅用于确保未计入未来的租赁日期.
使用seq几乎肯定是效率低下的-假设您的数据租约长达10,000年。seq将会花费永远,并返回对我们无关紧要的10000 * 365-1天。然后,我们必须使用%in%它进行相同数量的不必要的比较。
我不确定以下方法是否是最佳方法(我相信有一个完全矢量化的解决方案),但是它离问题的核心越来越近。
set.seed(102349)
days<-data.frame(AllDays=seq(as.Date("2012-01-01"),
as.Date("2015-08-18"),"day"))
leases<-data.frame(StartDate=sample(days$AllDays,5000L,T))
leases$EndDate<-leases$StartDate+round(rnorm(5000,mean=365,sd=100))
Run Code Online (Sandbox Code Playgroud)
使用data.table和sapply:
library(data.table)
setDT(leases); setDT(days)
days[,lease_count:=
sapply(AllDays,function(x)
leases[StartDate<=x&EndDate>=x,.N])][]
AllDays lease_count
1: 2012-01-01 5
2: 2012-01-02 8
3: 2012-01-03 11
4: 2012-01-04 16
5: 2012-01-05 18
---
1322: 2015-08-14 1358
1323: 2015-08-15 1358
1324: 2015-08-16 1360
1325: 2015-08-17 1363
1326: 2015-08-18 1359
Run Code Online (Sandbox Code Playgroud)
这正是foverlaps闪耀的问题:基于另一个data.frame对data.frame进行子集化(foverlaps似乎是为此目的而定制的).
基于@ MichaelChirico的数据.
setkey(days[, AllDays1:=AllDays,], AllDays, AllDays1)
setkey(leases, StartDate, EndDate)
foverlaps(leases, days)[, .(lease_count=.N), AllDays]
# user system elapsed
# 0.114 0.018 0.136
# @MichaelChirico's approach
# user system elapsed
# 0.909 0.000 0.907
Run Code Online (Sandbox Code Playgroud)
以下是@Arun如何工作的简要说明,让我开始使用data.table.