resetting cumsum if value goes to negative in r

假如想象 提交于 2019-11-28 01:59:19

问题


ve <- c(17, -9, 9, -17, 17, -17, 11, -9, 16, -18, 17, 0, 0, -18, 17, 0, 0, -17, 14, -14, 17, -2, 0, -15, 9, -9, 17, -16, 16, -17, 17, -17, 17, -17, 17, -17, 17, -8, 7, -16, 17, -14, 14, -10, 10, -16, 16, -10, 10, -12, 12, -11, 11, -17, 17, -17, 17, -9, 8, -17, 17, -17, 17, -16, 16, -17, 17, -8, 8, -9, 9, -17, 17, -17, 17, -13, 13, -10, 7, -10, 13, -16, 17, -13, 13, -13, 13, -9, 8, -17, 17, -10, 9, -17, 17, -17, 17, -16, 16, -10, 10, -15, 15, -14, 14, -14, 15, -13, 13, -9, 9, -13, 13, -12, 12, -10, 9, -11, 12, -8, 7, -10, 10, -9, 9, -11, 11, -9, 9, -7, 7, -12, 11, -11, 12, -11, 11, -14, 14, -13, 13, -10, 10, -13, 13, -17, 17, -7, 7, -17, 17, -17, 17, -14, 14, NA)

df <- data.frame(ve = ve, calc = 0)

I need to calculate cumsum in column calc, but it needs to reset to zero and start again whenever its value goes negative.. I've tried several conditions but it's not really working...

Also, is it possible to achieve this in dplyr? I'm new to dplyr and find it somewhat difficult whenever I need to use dependent value..

Thank you for your help!

it should go as..

     ve calc
1    17    17
2    -9    8
3     9    17
4   -17    0
5    17    17
6   -17    0
7    11    11
8    -9    2
9    16    18
10  -18    0
11   17    17
12    0    17
13    0    17
14  -18    0
15   17    17

If you see row 14 and 15, with the normal cumsum it would be -1 and 16 but I want it to reset to 0 instead of -1 and continue cumsum, hence the next would be 17


回答1:


We can replace the NA values with 0 and use cumsum

library(dplyr)
df1 <- df %>%
      group_by(grp = cumsum(lag(cumsum(replace(ve, is.na(ve), 0)) < 0, default = TRUE))) %>%
     mutate(calc = cumsum(replace(ve, is.na(ve), 0)), calc = replace(calc, calc < 0, 0)) %>%
      ungroup() %>%
      select(-grp)
head(df1, 15)
# A tibble: 15 x 2
#      ve  calc
#   <dbl> <dbl>
# 1    17    17
# 2    -9     8
# 3     9    17
# 4   -17     0
# 5    17    17
# 6   -17     0
# 7    11    11
# 8    -9     2
# 9    16    18
#10   -18     0
#11    17    17
#12     0    17
#13     0    17
#14   -18     0
#15    17    17



回答2:


Here is an iterative solution. I can't think of how to do this vectorized/using dplyr without multiple passes over the data, but I'm sure someone else will:

ve_csum = numeric(length(ve))

current_total = 0
for (i in 1:length(ve)) {
    if (is.na(ve[i])) {
        ve_csum[i] = current_total
        next
    }
    current_total = current_total + ve[i]
    if (current_total < 0) {
        current_total = 0
    }
    ve_csum[i] = current_total
}

result = data.frame(ve, ve_csum)



回答3:


Not using dplyr, but this should work:

ve = as.data.frame(ve)
ve = na.omit(ve)
ve$cumS = 0
ve$cumS[1] = ve$ve[1]

for (i in 2 : length(ve$ve)) {

ve$cumS[i] = ifelse((ve$cumS[i - 1] + ve$ve[i]) < 0,
                     0, (ve$cumS[i - 1] + ve$ve[i]))
}



回答4:


> df$calc=ifelse(cumsum(df$ve)<0,0,cumsum(df$ve))


来源:https://stackoverflow.com/questions/44512075/resetting-cumsum-if-value-goes-to-negative-in-r

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!