系统自学R的第八天#参考书籍《R语言编程艺术》

今日略晚,明天开组会,还在思考要汇报些什么呢。。。。
好了,多点少点,学习了就是好的。。
今天看的是一个案例:预测离散值时间序列

假设我们观察到取值为0或1的数据,每个时刻一个值。
假设这是每天的天气数据:1代表有雨,0代表没有雨。
假设已经知道最近几天是否下雨,我们希望预测明天是否会下雨。
具体而言,对于某个k值,我们会根据最近k天的天气记录来预测明天的天气。
我们将使用“过半数规则”(majorityrule):
如果在最近k期里1的数量大于等于k/2,那么预测下一个值为1,否则,预测下一个值为0。例如如果k=3,最近三期的数据为1、0、1,则预测下一期值为1。

但是,***我们应该如何选择k?***显然,如果选择的值太小,则给我们用以预测的样本量太小。
如果取值过大,导致我们使用过于早期的数据,而这些数据只有很少或根本没有预测价值。

一个解决方案是针对已知的数据(称为训练集),变换不同的k值,看看预测效果如何
在天气的例子中,假设我们有500天的数据,假设我们考虑使用k=3。为了评价k值的预测能力,我们基于前三天的数据来“预测”每天的数据,然后将预测值与已知值进行对比。以此类推,对于k=1、k=2、k=4,我们做同样的事情,直到k值足够大。
然后,我们使用训练数据中表现最好的k值,用于未来的预测
以下是一个可以实现的代码:

preda<-function(x,k){
  n<-length(x) 
  k2<- k/2
  # the vector pred will contain our predicted values 
  pred<-vector(length=n-k) 
  for(i in 1:(n-k)){
  if(sum(x[i:(i+(k-1))])>=k2) pred[i]<- 1 else pred[i] <- 0}
return(mean(abs(pred-x[(k+1):n])))}

这段代码的核心在第7行。此处要预测第i+k天的值(预测结果保存在pred[i]),利用的是之前k天的值,也即第i天,……,第i+k-1天的值。因此,我们需要算出这些天中1的个数。由于我们处理的是0-1数据,1的数量可以简单地使用这些天x[il的总和,它可以很方便地用以下方法获取:

sum(x[i:(i+(k-1))])

使用sum()函数和向量索引使得计算更简捷,避免了循环,因此它更简单更快速。这是R语言典型的用法。
第9行的表达式也是同样的道理:

mean(abs(pred-x[(k+1):n]))

在这里,pred包含预测值,而x[(k+1):n]是这些天的实际值。前者减去后者,得到的值要么为0,要么为1,或-1。在这里,1或-1对应两个方向的预测误差,即当真实值为1时预测值为0,或者真实值为0时预测为1。再用abs()函数求出绝对值,得到0和1的序列,后者表示预测有误差。
这样,我们就能知道哪些天的预测有误差,然后使用mean()来计算错误率,在这里我们应用了这一数学原理:即0-1数据的均值是1的比例。这是R语言的一个常见技巧。

上述preda()的编码是相当直截了当的,它的优点是简单和紧凑。然而,它可能很慢。我们可以尝试用向量化循环来加快速度。然而在这里它不能解决加速的主要障碍,即这些代码中所有的重复计算都不能避免。在循环中对于i的相邻两个取值,调用sum()函数求和的向量只相差两个元素。这会减慢速度,除非k值非常小。
所以,我们重写代码,计算过程中利用上一步计算的结果。在循环的每一次迭代中,将更新前一次得到的总和,而不是从头开始计算新的总和。

predb <- function(x,k){
  n <- length(x) 
  k2 <- k/2 
  pred < -vector(length=n-k) 
  sm<- sum(x[1:k])
  if(sm >=k2) pred[1] <- 1 else pred[1] <- 0 
  if (n-k >= 2) {
    for (i in 2:(n-k)) {
      sm<-sm+x[i+k-1]-x[i-1]
      if(sm >= k2) pred[i] <- 1 else pred[i] <-0
    }
  }
          return(mean(abs(pred-x[(k+1):n])))
}

关键在第9行。在这里从总和sm里减去最早的元素x[i-1],再加上新的元素(x[i+k-1]),从而更新sm。
另一种方法是使用R函数cumsum(),它能计算向量的累积和(cumulativesums)。这里是一个例子:

> y<-c(5,2,-3,8)
> cumsum(y)
[1]  5  7  4 12

在这里,y的累加和是5=5,5+2=7,5+2+(-3)=4,5+2+(-3)+8=12,这些值由 cumsum()返回。
在上面的例子里,建议用cumsum()的差值替代preda()中的表达式sum(x[i:(i+(k-1))。

predc <- function(x,k){
  n <- length(x) 
  k2<- k/2
  # the vector red will contain our predicted values 
  pred<-vector(length=n-k) 
  CSX<-c(0,cumsum(x)) 
  for (i in 1:(n-k)) {
  if(csx[i+k] -csx[i]>=k2) pred[i]<- 1 else pred[i]<- 0
  }
  return(mean(abs(pred-x[(k+1):n])))
}

在求x中连续k个元素(称为窗口)之和的时候,没有像下面这样使用sum()函数:

sum(x[i:(i+(k-1))

而是计算窗口的结束和开头处的累积和之差,像这样:

csx[i+k]-csx[i]

注意,我们在向量的累积和前面添加了0:

csx<-c(ocumsum(x))

这是为了保证在i=1时能计算出正确的值。
predb()函数里每次循环迭代要做两次减法运算,对predc()来说只需要做一次。
好的,我居然为了完成任务直接完全没读懂,笑了
明天继续吧!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值