Cumulative sum for positive numbers only

前端 未结 9 1190
梦谈多话
梦谈多话 2020-12-09 08:13

I have this vector :

x = c(1,1,1,1,1,0,1,0,0,0,1,1)

And I want to do a cumulative sum for the positive numbers only. I should have the fol

相关标签:
9条回答
  • 2020-12-09 08:39

    split and lapply version:

    x <- c(1,1,1,1,1,0,1,0,0,0,1,1)
    unlist(lapply(split(x, cumsum(x==0)), cumsum))
    

    step by step:

    a <- split(x, cumsum(x==0)) # divides x into pieces where each 0 starts a new piece
    b <- lapply(a, cumsum)  # calculates cumsum in each piece
    unlist(b)  # rejoins the pieces 
    

    Result has useless names but is otherwise what you wanted:

    # 01 02 03 04 05 11 12  2  3 41 42 43 
    #  1  2  3  4  5  0  1  0  0  0  1  2 
    
    0 讨论(0)
  • 2020-12-09 08:42

    Here is another base R solution using aggregate. The idea is to make a data frame with x and a new column named x.1 by which we can apply aggregate functions (cumsum in this case):

    x <- c(1,1,1,1,1,0,1,0,0,0,1,1)
    r <- rle(x)
    df <- data.frame(x, 
    x.1=unlist(sapply(1:length(r$lengths), function(i) rep(i, r$lengths[i]))))
    
    # df
    
       # x x.1
    # 1  1   1
    # 2  1   1
    # 3  1   1
    # 4  1   1
    # 5  1   1
    # 6  0   2
    # 7  1   3
    # 8  0   4
    # 9  0   4
    # 10 0   4
    # 11 1   5
    # 12 1   5
    
    agg <- aggregate(df$x~df$x.1, df, cumsum)
    as.vector(unlist(agg$`df$x`))
    
    # [1] 1 2 3 4 5 0 1 0 0 0 1 2
    
    0 讨论(0)
  • 2020-12-09 08:43

    One option is

    x1 <- inverse.rle(within.list(rle(x), values[!!values] <- 
                      (cumsum(values))[!!values]))
    x[x1!=0] <- ave(x[x1!=0], x1[x1!=0], FUN=seq_along)
    x
    #[1] 1 2 3 4 5 0 1 0 0 0 1 2
    

    Or a one-line code would be

     x[x>0] <-  with(rle(x), sequence(lengths[!!values]))
     x
     #[1] 1 2 3 4 5 0 1 0 0 0 1 2
    
    0 讨论(0)
  • 2020-12-09 08:45

    Base R, one line solution with Map Reduce :

    > Reduce('c', Map(function(u,v) if(v==0) rep(0,u) else 1:u, rle(x)$lengths, rle(x)$values))
     [1] 1 2 3 4 5 0 1 0 0 0 1 2
    

    Or:

    unlist(Map(function(u,v) if(v==0) rep(0,u) else 1:u, rle(x)$lengths, rle(x)$values))
    
    0 讨论(0)
  • 2020-12-09 08:45

    Try this one-liner...

    Reduce(function(x,y) (x+y)*(y!=0), x, accumulate=T)
    
    0 讨论(0)
  • 2020-12-09 08:46

    Here's a possible solution using data.table v >= 1.9.5 and its new rleid funciton

    library(data.table)
    as.data.table(x)[, cumsum(x), rleid(x)]$V1
    ## [1] 1 2 3 4 5 0 1 0 0 0 1 2
    
    0 讨论(0)
提交回复
热议问题