R 分析期间的日期范围

Range of dates in a period of analysis in R

我有一个包含三列的数据框 Data1NoContractIniDateFinDate 表示合同的标识符、合同何时开始以及何时结束分别。另一方面,我有一个分析期:2012 年 1 月 1 日至 2014 年 12 月 31 日。我想找出分析期每个月有多少活跃合约,活跃是指合约至少有一天在一个月的分析期中 IniDateFinDate 之间的日期。

我尝试在 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每一行的日期序列,并证明它是否在当前行的日期序列内Data1。此函数 returns 一个矩阵,其中行代表合同,列代表从 2012 年 1 月到 2014 年 12 月的月份,如果合同在一个月内有效,每个单元格都有 1,如果没有,则每个单元格有 0 (参见 Res)。最后我用 apply to sum by column 得到了我想要的。

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

案例是我实际Data1里面有几十万行(550K),运行myfun上面效率很低。我的问题是,也许是一种在 R 中有效执行此操作的方法?或者任何关于如何改进我的代码的建议。谢谢社区。

此处使用 data.table foverlaps 的选项。

  1. 首先,foverlaps是使用区间的合并。您应该具有相同的列名才能进行合并。您还应该设置第二个 table.
  2. 的键
  3. LThe desired output is a matrix where rows represent a contract and columns months from Jan 2012 to Dec 2014=],所以我创建了一个新的列周期,它是年月合同。
  4. 使用 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