如何以编程方式根据以前的日期对R中的日期进行子集化?

时间:2017-04-19 02:53:35

标签: r function date subset xts

我试图在R中编写一个函数来以编程方式选择一组日期,每次迭代都依赖于之前的日期选择。我无法解决的挑战是如何系统地分析数据集,在分析的每个阶段选择日期,然后使用该日期作为选择下一个日期的起点。对于每次新迭代,一次一个地执行此操作是微不足道的。问题是如何编写一个函数,当数据集中没有剩余日期满足条件时,该函数将自动停止?我知道有一个解决方案,可能使用for()和/或while()循环,可能还有break()命令。但到目前为止,我无法找到答案。任何帮助,将不胜感激。作为我试图解决的过程的一个简单例子:

 # create fake data for 12 months with dates
library("xts")
 set.seed(67)
 dat <-xts(rnorm(12)+100,seq(as.Date("2001/1/1"), as.Date("2001/12/1"),    "1 months"))

查看原始数据:

 dat
                 [,1]
 2001-01-01 101.21940
 2001-02-01  99.87560
 2001-03-01  99.04250
 2001-04-01  99.92083
 2001-05-01  98.85659
 2001-06-01  98.94281
 2001-07-01  99.61547
 2001-08-01 100.60834
 2001-09-01 101.67247
 2001-10-01  98.46271
 2001-11-01  98.62171
 2001-12-01 100.49543

接下来,创建第一个选择第一个日期的函数,在这种情况下只需选择第二个日期条目:

f.1 <-function(x) { 
a <-as.Date(index(dat[2]))
 }

创建第二个函数,查看第一个日期之后的日期,并选择那些日期&gt; 101。

 f.2 <-function(x,y) { # x=dat, y=previous foo.date
   a <-x[paste0(y+1, "/")]
   b <-as.Date(index(a[a >101]))
 }

最后,运行函数并收集日期......

 foo.date.1 <-f.1(dat)
 foo.date.2 <-f.2(dat,foo.date.1)
 foo.date.3 <-f.2(dat,foo.date.2)

汇总3个foo.date文件的输出:

 dat.all <-c(foo.date.1, foo.date.2, foo.date.3)
 dat.all
 [1] "2001-02-01" "2001-09-01"

请注意,所选的最后日期是foo.date.2。第三次尝试 - 根据foo.date.3 - 没有执行,因为2001-09-01之后没有值超过101的日期。然而,对于具有数千甚至数万个日期的数据集,找到与标准匹配的确切日期集是非常低效的。有关如何以编程方式找到解决方案的任何想法?在上面的例子中,通过函数的解决方案将a)发现只有2个日期符合标准,因此函数将在第二次尝试之后结束而不是尝试第三次搜索; b)在一个文件输出中汇总相关日期。

提前感谢您的任何答案!

2 个答案:

答案 0 :(得分:1)

如果我理解正确,你想找到每次观察后观察的指数值&gt; 101。

一个简单有效的解决方案是首先lag你的系列,然后简单地选择&gt;的观察的所有索引值。 101。

datlag <- lag(dat)
index(datlag[datlag > 101])
# [1] "2001-02-01" "2001-10-01"

基于此评论:

  

他的“标准”(目标)是确定投资组合中的权重偏离目标权重x(对于给定的回报系列)的日期。这对每个日期都很容易,一次一个。第一个函数标识第一个日期;第二个函数与使用前一个日期的区别相同。第二个功能可能会重复,具体取决于第一个功能超出第一个功能。#/ p>

问题似乎是真正的递归,这是使用循环的一个很好的理由(尽管你仍然需要注意在循环中增长对象)。

在这种情况下,您会定期将投资组合权重重置为目标。这意味着您必须重新计算所有未来的投资组合余额。

以下是2个资产的示例。

# asset return data
set.seed(67)
dat <- xts(matrix(rnorm(24, 0, 0.02),12,2),
           seq(as.Date("2001/1/1"), as.Date("2001/12/1"), "1 months"))

# constraints
target_weights <- c(0.5, 0.5)
tol <- 0.01                # each asset must be +/-1% of its target
rebal_dates <- start(dat)  # assume allocation on first observation

# loop until break
while (last(rebal_dates) < end(dat)) {
  # date range, starting from period after last rebalance date
  date_range <- paste0(last(rebal_dates) + 1, "/")
  # portfolio balance over date range
  bal <- cumprod(1 + dat[date_range,])
  # portfolio weights
  wts <- bal / rowSums(bal)
  # deviations from target portfolio
  dev <- abs(wts - rep(target_weights, nrow(wts))) > tol
  # next rebalance date
  next_rebal <- which(rowSums(dev) > 0)
  # break the loop if there are no more rebalance dates
  if (length(next_rebal) == 0)
    break
  # append rebalance date to our vector
  # (yes, this is growing an object, but it's small and not very frequent)
  rebal_dates <- c(rebal_dates, index(dev)[next_rebal[1]])
}
rebal_dates
# [1] "2001-01-01" "2001-06-01" "2001-09-01" "2001-10-01" "2001-11-01"

答案 1 :(得分:0)

我不熟悉xts格式,因此我使用标准数据框重新创建了数据,date:日期字段和x:随机值。

set.seed(4)
dat <- data.frame(date=as.Date(paste0("2001-", 1:12, "-1")), x=rnorm(12)+100)
head(dat)

        date         x
1 2001-01-01 100.21675
2 2001-02-01  99.45751
3 2001-03-01 100.89114
4 2001-04-01 100.59598
5 2001-05-01 101.63562
6 2001-06-01 100.68928    

提取x > 101的日期:

lapply(1:nrow(dat), function(x){
  d2 <- dat[x:nrow(dat), ] 
  d2[d2$x > 101, "date"]
})

[[1]]
[1] "2001-05-01" "2001-09-01" "2001-10-01"

[[2]]
[1] "2001-05-01" "2001-09-01" "2001-10-01"

[[3]]
[1] "2001-05-01" "2001-09-01" "2001-10-01"

[[4]]
[1] "2001-05-01" "2001-09-01" "2001-10-01"

[[5]]
[1] "2001-05-01" "2001-09-01" "2001-10-01"

[[6]]
[1] "2001-09-01" "2001-10-01"

[[7]]
[1] "2001-09-01" "2001-10-01"

[[8]]
[1] "2001-09-01" "2001-10-01"

[[9]]
[1] "2001-09-01" "2001-10-01"

[[10]]
[1] "2001-10-01"

[[11]]
character(0)

[[12]]
character(0)