2011-12-16 87 views
2

我有这个数据帧有条件的累积和

t<-data.frame(v1=c(1,2,1,4,6,7,8,2,3,4,8,1,2), v2=c(2,3,6,1,-3,-2,1,2,-3,6,7,-2,1)) 

从顶部扫描data.frame至底部,我想V1的累积和,只要v2是积极的。当v2变为负数时,它应该停止,记录(之前的cum.sum的值),累积和应该从下一个第一个正值v2重新开始,等等。因此,最终的上述数据帧将是矢量

8, 10 , 12, 2 

任何想法?

+0

如果只想总和,为什么要用cumsum? – 2011-12-16 17:36:12

回答

3

这是另一种方法。

> r <- rle(sign(t$v2)) 
> diff(c(0,cumsum(t$v1)[cumsum(r$lengths)]))[r$values==1] 
[1] 8 10 12 2 

如果将其分开,则更容易理解;它通过挑选累积和的正确元素并减去它们来工作。

> (s <- cumsum(t$v1)) 
[1] 1 3 4 8 14 21 29 31 34 38 46 47 49 
> (r <- rle(sign(t$v2))) 
Run Length Encoding 
    lengths: int [1:7] 4 2 2 1 2 1 1 
    values : num [1:7] 1 -1 1 -1 1 -1 1 
> (k <- cumsum(r$lengths)) 
[1] 4 6 8 9 11 12 13 
> (a <- c(0,s[k])) 
[ 1] 0 8 21 31 34 46 47 49 
> (d <- diff(a)) 
[1] 8 13 10 3 12 1 2 
> d[r$values==1] 
[1] 8 10 12 2 

类似的,但没有rle

> k <- which(diff(c(sign(t$v2),0))!=0) 
> diff(c(0,cumsum(t$v1)[k]))[t$v2[k]>0] 
[1] 8 10 12 2 
4

这里有一种方法:

t <- data.frame(v1=c(1,2,1,4,6,7,8,2,3,4,8,1,2), v2=c(2,3,6,1,-3,-2,1,2,-3,6,7,-2,1)) 

unname(with(t, tapply(v1[v2>0], cumsum(abs(diff(sign(c(0,v2)))))[v2>0], sum))) 
[1] 8 10 12 2 

这似乎起初有点复杂:) 的cumsum(abs(diff(sign(c(0,v2)))))生成正值或负值的每次运行一个唯一的组ID。使用diffcumsum是因为这是一个“常见”技巧,很好理解......一个障碍是diff产生一个较短的向量 - 这就是为什么使用c(0, v2)

5

我改变了data.frame的名字,因为t是一个函数(转置)。我不明白为什么你想要使用cumsum如果你只想要的总和。

dtf<-data.frame(v1=c(1,2,1,4,6,7,8,2,3,4,8,1,2), v2=c(2,3,6,1,-3,-2,1,2,-3,6,7,-2,1)) 
groups <- rle(dtf$v2 > 0) 

dtf$groups<- rep(seq_along(groups$values), groups$lengths) 
library(plyr) 
daply(dtf, .(groups), function(x) sum(x$v1))[groups$values] 
1 3 5 7 
8 10 12 2