2011-12-16 25 views
2

私は、このデータフレーム上から下へdata.frameをスキャン条件付き累積和

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)) 

を持って、私は限りV2は正であるとするために、V1の累積合計を取得したいです。 v2が負になると停止し、その時点までのcum.sumの値を記録し、累積合計は次の最初の肯定的なv2から再開する必要があります。したがって、上記のデータフレームの最後にはベクトルになります

8, 10 , 12, 2 

アイデアをお持ちですか?

+0

あなただけの合計をしたい場合は、理由を使用しCUMSUM? –

+0

@Iselzer - そうですね、それは「条件付き合計」のようです... – Tommy

答えて

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

ここに1つの方法です:

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

tが関数(転置)であるため、data.frameの名前を変更しました。私はあなたが唯一の和をしたい場合はなぜ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