R中分析期间的日期范围

时间:2015-06-09 20:52:52

标签: r date date-range

我有一个数据框Data1,其中有三列:NoContractIniDateFinDate表示合同的标识符,合同开始时和分别结束时。另一方面,我有一段时间的分析: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的每一行的日期序列,并证明它是否在当前行{的日期序列中{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。

1 个答案:

答案 0 :(得分:3)

这是一个使用data.table foverlaps

的选项
  1. 首先,foverlaps是使用间隔的合并。您应该使用相同的列名来进行合并。您还应该设置第二个表的键。
  2. LT所需的输出是一个矩阵,其中行代表合约和2012年1月至2014年12月的列数,因此我创建了一个新的列期间,即合同的年月。
  3. 使用dcast.data.table
  4. 以宽格式重塑结果

    代码:

    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