Search code examples
rloopsdataframeif-statementcumsum

R: Sum until 0 is reached and then restart


Adding on to what's already being said or commented on this post: Cumulative sum until maximum reached, then repeat from zero in the next row

I've a similar dataframe which has about 50k+ observations. This dataframe was being read from a csv file and is an outcome of several operations already performed on it. Pasting a sample here:

          Home      Date     Time   Appliance Run   value
    679      2  1/21/2017  1:30:00          0   1       0
    680      2  1/21/2017  1:45:00          0   1       0
    681      2  1/21/2017  2:00:00          0   1       0
    682      2  1/21/2017  2:15:00          0   1       0
    683      2  1/21/2017  2:30:00        804   0       1
    684      2  1/21/2017  2:45:00        556   0     804
    685      2  1/21/2017  3:00:00        844   0    1360
    686      2  1/21/2017  3:15:00        396   0    2204
    687      2  1/21/2017  3:30:00        392   0    2600
    688      2  1/21/2017  3:45:00       1220   0    2992
    689      2  1/21/2017  4:00:00          0   1       0
    690      2  1/21/2017  4:15:00          0   1       0
    691      2  1/21/2017  4:30:00          0   1       0
    692      2  1/21/2017  4:45:00          0   1       0
    783      2  1/22/2017  3:30:00          0   1       0
    784      2  1/22/2017  3:45:00        244   0    4212
    785      2  1/22/2017  4:00:00       1068   0    4456
    786      2  1/22/2017  4:15:00         44   0    5524
    787      2  1/22/2017  4:30:00       1240   0    5568
    788      2  1/22/2017  4:45:00         40   0    6808
    789      2  1/22/2017  5:00:00       1608   0    6848
    790      2  1/22/2017  5:15:00          0   1       0
    791      2  1/22/2017  5:30:00          0   1       0

The code I used, given as one of the answers, df = transform(df, value = ave(Appliance, Run, FUN = function(x)c(1, head(cumsum(x),-1)))).

However, as you can see in the output, the sums won't restart at the next occurrence of 0 plus the last sum for first group (683-688 index) is carry forwarded to 784 (index number). Please help me in restarting the sums at next occurrence of 0.

Expected output:

          Home       Date     Time  Appliance Run   value
    679      2  1/21/2017  1:30:00          0   1       0
    680      2  1/21/2017  1:45:00          0   1       0
    681      2  1/21/2017  2:00:00          0   1       0
    682      2  1/21/2017  2:15:00          0   1       0
    683      2  1/21/2017  2:30:00        804   0     804
    684      2  1/21/2017  2:45:00        556   0    1360
    685      2  1/21/2017  3:00:00        844   0    2204
    686      2  1/21/2017  3:15:00        396   0    2600
    687      2  1/21/2017  3:30:00        392   0    2992
    688      2  1/21/2017  3:45:00       1220   0    4212
    689      2  1/21/2017  4:00:00          0   1       0
    690      2  1/21/2017  4:15:00          0   1       0
    691      2  1/21/2017  4:30:00          0   1       0
    692      2  1/21/2017  4:45:00          0   1       0
    783      2  1/22/2017  3:30:00          0   1       0
    784      2  1/22/2017  3:45:00        244   0     244
    785      2  1/22/2017  4:00:00       1068   0    1312
    786      2  1/22/2017  4:15:00         44   0    1356
    787      2  1/22/2017  4:30:00       1240   0    2596
    788      2  1/22/2017  4:45:00         40   0    2636
    789      2  1/22/2017  5:00:00       1608   0    4244
    790      2  1/22/2017  5:15:00          0   1       0
    791      2  1/22/2017  5:30:00          0   1       0

P.S: I've already tried this too: Sum until a given value is reached


Solution

  • Here is a data.table option. Your grouping variable should not be Run but rleid(Run).

    library(data.table)
    dt <- fread(text)
    dt[, value := cumsum(Appliance), by = rleid(Run)]
    dt
    #     V1 Home      Date    Time Appliance Run value
    # 1: 679    2 1/21/2017 1:30:00         0   1     0
    # 2: 680    2 1/21/2017 1:45:00         0   1     0
    # 3: 681    2 1/21/2017 2:00:00         0   1     0
    # 4: 682    2 1/21/2017 2:15:00         0   1     0
    # 5: 683    2 1/21/2017 2:30:00       804   0   804
    # 6: 684    2 1/21/2017 2:45:00       556   0  1360
    # 7: 685    2 1/21/2017 3:00:00       844   0  2204
    # 8: 686    2 1/21/2017 3:15:00       396   0  2600
    # 9: 687    2 1/21/2017 3:30:00       392   0  2992
    #10: 688    2 1/21/2017 3:45:00      1220   0  4212
    #11: 689    2 1/21/2017 4:00:00         0   1     0
    #12: 690    2 1/21/2017 4:15:00         0   1     0
    #13: 691    2 1/21/2017 4:30:00         0   1     0
    #14: 692    2 1/21/2017 4:45:00         0   1     0
    #15: 783    2 1/22/2017 3:30:00         0   1     0
    #16: 784    2 1/22/2017 3:45:00       244   0   244
    #17: 785    2 1/22/2017 4:00:00      1068   0  1312
    #18: 786    2 1/22/2017 4:15:00        44   0  1356
    #19: 787    2 1/22/2017 4:30:00      1240   0  2596
    #20: 788    2 1/22/2017 4:45:00        40   0  2636
    #21: 789    2 1/22/2017 5:00:00      1608   0  4244
    #22: 790    2 1/22/2017 5:15:00         0   1     0
    #23: 791    2 1/22/2017 5:30:00         0   1     0
    #24: 792    2 1/22/2017 5:45:00         0   1     0
    #25: 793    2 1/22/2017 6:00:00         0   1     0
    #26: 794    2 1/22/2017 6:15:00         0   1     0
    #27: 795    2 1/22/2017 6:30:00         0   1     0
    #28: 796    2 1/22/2017 6:45:00         0   1     0
    #29: 797    2 1/22/2017 7:00:00         0   1     0
    #30: 798    2 1/22/2017 7:15:00         0   1     0
    

    In base R we can do

    df1 <- read.table(text = text, stringsAsFactors = FALSE, header = TRUE)
    
    rle_Run <- rle(df1$Run)
    df1$value <- with(df1, ave(Appliance, rep(seq_along(rle_Run$lengths), rle_Run$lengths), FUN = cumsum))
    

    data

    text <- "          Home      Date     Time   Appliance Run   value
        679      2  1/21/2017  1:30:00          0   1       0
    680      2  1/21/2017  1:45:00          0   1       0
    681      2  1/21/2017  2:00:00          0   1       0
    682      2  1/21/2017  2:15:00          0   1       0
    683      2  1/21/2017  2:30:00        804   0       1
    684      2  1/21/2017  2:45:00        556   0     804
    685      2  1/21/2017  3:00:00        844   0    1360
    686      2  1/21/2017  3:15:00        396   0    2204
    687      2  1/21/2017  3:30:00        392   0    2600
    688      2  1/21/2017  3:45:00       1220   0    2992
    689      2  1/21/2017  4:00:00          0   1       0
    690      2  1/21/2017  4:15:00          0   1       0
    691      2  1/21/2017  4:30:00          0   1       0
    692      2  1/21/2017  4:45:00          0   1       0
    783      2  1/22/2017  3:30:00          0   1       0
    784      2  1/22/2017  3:45:00        244   0    4212
    785      2  1/22/2017  4:00:00       1068   0    4456
    786      2  1/22/2017  4:15:00         44   0    5524
    787      2  1/22/2017  4:30:00       1240   0    5568
    788      2  1/22/2017  4:45:00         40   0    6808
    789      2  1/22/2017  5:00:00       1608   0    6848
    790      2  1/22/2017  5:15:00          0   1       0
    791      2  1/22/2017  5:30:00          0   1       0
    792      2  1/22/2017  5:45:00          0   1       0
    793      2  1/22/2017  6:00:00          0   1       0
    794      2  1/22/2017  6:15:00          0   1       0
    795      2  1/22/2017  6:30:00          0   1       0
    796      2  1/22/2017  6:45:00          0   1       0
    797      2  1/22/2017  7:00:00          0   1       0
    798      2  1/22/2017  7:15:00          0   1       0"