我有一个数据框Data1
,其中有三列:NoContract
,IniDate
,FinDate
表示合同的标识符,合同开始时和分别结束时。另一方面,我有一段时间的分析:2012年1月1日到2014年12月31日。我想找到分析期间每个月活跃的合约数量,我认为合约至少有一天在一个月的分析期内,其日期在IniDate
和FinDate
之间。
我在R做过尝试:
让我们说Data1
是:
Data1 <- data.frame(NoContract= 1:3, IniDate= as.Date(c("2011-05-03","2012-03-13","2014-03-26")),FinDate=as.Date(c("2015-01-05","2013-03-13","2015-08-19")))
Data1
NoContract IniDate FinDate
1 1 2011-05-03 2015-01-05
2 2 2012-03-13 2013-03-13
3 3 2014-03-26 2015-08-19
我已经创建了另一个数据框DatesCalc:
DatesCalc<-data.frame(monthI=seq(as.Date("2012-01-01"), as.Date("2014-12-31"), by="1 month"), monthF=(seq(as.Date("2012-02-01"), as.Date("2015-01-01"), by="1 month")-1))
head(DatesCalc)
monthI monthF
1 2012-01-01 2012-01-31
2 2012-02-01 2012-02-29
3 2012-03-01 2012-03-31
4 2012-04-01 2012-04-30
5 2012-05-01 2012-05-31
6 2012-06-01 2012-06-30
接下来,我写了一个函数
myfun<-function(X,Y){
d1<-numeric()
d2<-numeric()
for (i in 1:36){ #36 num of rows on DatesCalc
d1<-numeric()
for (j in 1:3){ #3 num of rows of my Data1 (my actual case near 550K rows)
d1<-c(d1,sum(seq(X[i,1],X[i,2],by=1)%in%seq(Y[j,2],Y[j,3],by=1),na.rm=TRUE)>0)
}
d2<-cbind(d2,d1)
}
return(d2)
}
它的作用是,对于Data1
的每一行,创建DatesCalc
的每一行的日期序列,并证明它是否在当前行{的日期序列中{1}}。此函数返回一个矩阵,其中行表示2012年1月至2014年12月期间的合同和列数,如果合同处于活动状态,则每个单元格为Data1
,否则为1
(请参阅{{ 1}})。最后我使用了按柱的总和,得到了我想要的东西。
0
案例是我在实际的Res
中有数十万行(550K),并且在其上运行Res<-myfun(DatesCalc,Data1)
Res
d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1
[1,] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
[2,] 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
[3,] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1
apply(Res,2,sum)
d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1 d1
1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2
效率很低。我的问题是,也许是一种在R中实现这种效率的方法?或者有关如何改进我的代码的任何建议。谢谢Comunnity。
答案 0 :(得分:3)
这是一个使用data.table foverlaps
。
foverlaps
是使用间隔的合并。您应该使用相同的列名来进行合并。您还应该设置第二个表的键。dcast.data.table
代码:
library(data.table)
setDT(Data1)
setDT(DatesCalc)
setkey(Data1, IniDate, FinDate) ## Set keys for merge
setnames(DatesCalc,names(DatesCalc),c('IniDate','FinDate')) ## rename for merge
dcast.data.table( ## wide format
foverlaps(DatesCalc, Data1, type="within")[,
period := format(i.IniDate,'%Y-%m')], ## create a new variable here
NoContract~period,fun=length) ## the aggregate function is the length (T/F)
NoContract 2012-01 2012-02 2012-03 2012-04 2012-05 2012-06 2012-07 2012-08 2012-09 2012-10 2012-11 2012-12 2013-01 2013-02 2013-03 2013-04 2013-05 2013-06 2013-07
1: 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
2: 2 0 0 0 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0
3: 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2013-08 2013-09 2013-10 2013-11 2013-12 2014-01 2014-02 2014-03 2014-04 2014-05 2014-06 2014-07 2014-08 2014-09 2014-10 2014-11 2014-12
1: 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
2: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
3: 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1