[R] partial cumsum
Marc Schwartz
marc_schwartz at me.com
Thu Nov 12 00:20:03 CET 2009
On Nov 11, 2009, at 4:45 PM, Carl Witthoft wrote:
> By Bill Dunlap:
> quote:
> > x <- c(1, 2, 3, NA, 5, 6, 7, 8, 9, 10)
> > rev(cumsum(rev(is.na(x))))
> [1] 1 1 1 1 0 0 0 0 0 0
> A more natural way to do this is
> > cumsum(is.na(c(NA,x[-length(x)])))
> [1] 1 1 1 1 2 2 2 2 2 2
> endquote
>
> Both of which suggest the original problem could also be dealt with
> by using rle(). Something like
>
> xna<-is.na(x)
> rle(xna)
> and then apply cumsum to sections of x based onthe lengths returned
> by rle
>
> Carl
Which would be something along the lines of the following:
rle.x <- rle(!is.na(x))$lengths
> rle.x
[1] 3 1 6
> as.numeric(unlist(sapply(split(x, rep(seq(along = rle.x), rle.x)),
cumsum)))
[1] 1 3 6 NA 5 11 18 26 35 45
Which is what I had been working on until I saw Bill's more elegant
"one-liner" solution... :-)
The interim use of split() gets you 'x' split by where the NA's occur:
> rep(seq(along = rle.x), rle.x)
[1] 1 1 1 2 3 3 3 3 3 3
> split(x, rep(seq(along = rle.x), rle.x))
$`1`
[1] 1 2 3
$`2`
[1] NA
$`3`
[1] 5 6 7 8 9 10
and then you use cumsum() in sapply() (or lapply()) on each list
element and coerce the result back to an un-named numeric vector.
Regards,
Marc Schwartz
More information about the R-help
mailing list