我有这个数据框
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,只要v2为正,我想获得v1的累积和。当v2变为负数时,它应该停止,记录(到那时为止的cum.sum)的值,并且累计和应该从下一个第一个正v2重新开始,依此类推。因此,最终对于上述数据框将是向量
8, 10 , 12, 2
有什么想法吗?
答案 0 :(得分: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
答案 1 :(得分: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。使用diff
和cumsum
这是一个很常见的“常见”技巧......一个障碍是diff
生成一个更短的向量 - 这就是为什么c(0, v2)
使用。
答案 2 :(得分: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