【问题标题】:Efficient Manipulation of Time Series in R Data Table PackageR 数据表包中时间序列的高效处理
【发布时间】:2013-12-07 02:52:12
【问题描述】:

非常感谢您的评论/回答。

背景:我有一个包含十几个国家互换利率每日价格的大型数据表。这些列是 [ID, Date, X1Y, X2Y, X3Y ... X30Y],其中 X..Y 是表示收益率曲线部分的列(例如,X1Y 是 1 年期互换,X3Y 是 3 年期互换)。这两个键是ID(例如“AUD”、“GBP”)和Date(例如“2001-04-13”、“2001-04-16”)。

虚拟数据:

set.seed(123)
dt <- cbind(ID=rep(c("AUD","GBP"),c(100,100)),X1Y=rnorm(200),X2Y=rnorm(200),X3Y=rnorm(200))
dt <- data.table(dt)
dt[,Date := seq(from=as.IDate("2013-01-01"), by="1 day", length.out=100)]
setkeyv(dt,c("ID","Date"))

问题 1: 首先生成一些虚拟信号。如果有 100 列具有相当复杂的信号生成公式,在单独的函数中编码,比如 genSig(X1Y),那么语法是什么?这就是我只使用 3 列和一些无意义的公式的意思:

dt[,SIG1  :=c(0, diff(X1Y ,1)),by="ID"]
dt[,SIG2  :=c(0, diff(X2Y ,1)),by="ID"]
dt[,SIG3  :=c(0, diff(X3Y ,1)),by="ID"]

问题 2: 根据“月中”结转列。例如,使用 SIG 列,我想让每个月 15 日之后的所有内容都与 15 日的信号相同,直到下个月的 15 日。棘手的是,实际数据仅包含交易日,因此如果是周末/节假日,有些月份没有 15 日。另一个问题是使用有效的语法,我可以在每个月初使用循环(我知道..)来实现类似的东西,只是为了说明我的意思:

for (i in 2:length(dt$Date)){
  if(as.POSIXlt(dt[i,]$Date)$mon == as.POSIXlt(dt[i-1,]$Date)$mon){
    dt[i, SIG1 := dt[i-1,SIG1]] 
    dt[i, SIG2 := dt[i-1,SIG2]] 
    dt[i, SIG3 := dt[i-1,SIG3]] 
  }
}

我不知道如何处理“月中”问题,因为它可能在 15 日、16 日或 17 日发生。与问题 1 一样,如果有一种智能方法可以插入/更新多列/多列,将不胜感激。

【问题讨论】:

    标签: r time-series data.table


    【解决方案1】:
    # problem 1
    nsig <- 3L
    csig <- 1:nsig+1L
    newcols <- paste('SIG',1:nsig,sep='')
    dt[,(newcols):=0]
    for (j in csig) set(dt,j=j+nsig+1L,value=c(0, diff(dt[[j]],1)))
    

    查看@eddi 的回答后,我发现set 对于问题2 并没有那么有用。这就是我要做的:

    dt[,(newcols):=lapply(newcols,function(x) get(x)[1]),by=list(ID,month(Date-14))]
    

    根据this answer,您可以通过这种方式从日期中减去天数。


    除此之外。 Cbind-ing 向量构成一个矩阵。在您的示例中,您有一个字符矩阵。我想你在寻找...

    # Creating better data...
    set.seed(123)
    dt <- data.table(ID=rep(c("AUD","GBP"),c(100,100)),
      X1Y=rnorm(200),X2Y=rnorm(200),X3Y=rnorm(200),
      Date=seq(from=as.IDate("2013-01-01"), by="1 day", length.out=100))
    

    【讨论】:

    • 谢谢弗兰克。这有帮助!
    【解决方案2】:

    就问题 2 而言,您可以使用滚动连接:

    # small sample to demonstrate
    dt = data.table(date = as.Date(c('2013-01-01', '2013-01-15', '2013-01-17', '2013-02-14', '2013-02-17'), '%Y-%m-%d'), val = 1:5)
    dt
    #         date val
    #1: 2013-01-01   1
    #2: 2013-01-15   2
    #3: 2013-01-17   3
    #4: 2013-02-14   4
    #5: 2013-02-17   5
    
    setkey(dt, date)
    midmonth = seq(as.Date('2013-01-15', '%Y-%m-%d'),
                   as.Date('2013-12-15', '%Y-%m-%d'),
                   by = '1 month')
    
    dt[, flag := 0]
    dt[J(midmonth), flag := 1, roll = -Inf]
    dt
    #         date val flag
    #1: 2013-01-01   1    0
    #2: 2013-01-15   2    1
    #3: 2013-01-17   3    0
    #4: 2013-02-14   4    0
    #5: 2013-02-17   5    1
    

    现在您可以通过cumsum flag 获得您想要的分组,例如做:

    dt[, val1 := val[1], by = cumsum(flag)]
    dt
    #         date val flag val1
    #1: 2013-01-01   1    0    1
    #2: 2013-01-15   2    1    2
    #3: 2013-01-17   3    0    2
    #4: 2013-02-14   4    0    2
    #5: 2013-02-17   5    1    5
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-04
      • 2015-07-01
      相关资源
      最近更新 更多