鉴于以下数据:
sample <- xts(c( 1,1,1,1,1,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,1,1,1,1,1,3,3,3,3,3,3,4,4,4,4,4,4,2,2,1,1,1,1,4,4,4,4,4,4,4,4,4),
as.Date(x = "2014-11-03")+1:52)
我想制作以下内容:
[,1]
2014-11-05 0
2014-11-06 0
2014-11-07 0
2014-11-08 0
2014-11-09 1
2014-11-10 2
2014-11-11 3
2014-11-12 4
2014-11-13 5
2014-11-14 6
2014-11-15 7
2014-11-16 8
2014-11-17 9
2014-11-18 10
2014-11-19 11
2014-11-20 12
2014-11-21 13
2014-11-22 14
2014-11-23 15
2014-11-24 0
2014-11-25 0
2014-11-26 0
2014-11-27 0
2014-11-28 0
2014-11-29 1
2014-11-30 2
2014-12-01 3
2014-12-02 4
2014-12-03 5
2014-12-04 6
2014-12-05 7
2014-12-06 8
2014-12-07 9
2014-12-08 10
2014-12-09 11
2014-12-10 12
2014-12-11 1
2014-12-12 2
2014-12-13 0
2014-12-14 0
2014-12-15 0
2014-12-16 0
2014-12-17 1
2014-12-18 2
2014-12-19 3
2014-12-20 4
2014-12-21 5
2014-12-22 6
2014-12-23 7
2014-12-24 8
2014-12-25 9
换句话说,给定一系列正整数,我想做一个累积和,从观察值不等于1开始,并继续递增,直到观察值相对于先前的观察值减小。
这就是我的想法:
require('xts')
sample <- xts(c( 1,1,1,1,1,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,1,1,1,1,1,3,3,3,3,3,3,4,4,4,4,4,4,2,2,1,1,1,1,4,4,4,4,4,4,4,4,4),
as.Date(x = "2014-11-03")+1:52)
# a vector of endpoints
ep <- c(1,which(diff(lag(sample,k=-1))<0),length(sample))
res <- period.apply(sample,ep,function(x){
# Make the 1s into 0s
x[x==1]=0
# Make those that are not 0s into 1s
x[x!=0] = 1
# Now cumsum will give the desired results
cumsum(x)
})
res <- Reduce(rbind,res)
res
有没有更好的方法来重写这个?特别是,始终将第一个和最后一个索引放入端点是否正常并且period.apply()
中的函数能够以更简洁的方式重写吗?
答案 0 :(得分:5)
以下是使用ave
的替代方法:
out <- sample
out[] <- ave(sample != 1, cumsum(c(TRUE, diff(coredata(sample)) < 0)), FUN = cumsum)
identical(out[-1], res)
## [1] TRUE
更新一些代码简化。
答案 1 :(得分:4)
使用data.table的另一种选择:
data.table(coredata(sample))[
,list(cum={V1[V1==1] <- 0; cumsum(V1!=0)}),
list(grp=cumsum(c(0,diff(V1))<0))]
编辑:缩进代码和更好的语法