I'm looking for a way to cumsum a column (by group) but with specific conditions.
My conditions are :
- Add a starting value
- The sum is restricted by upper & lower limits
I've done it with an iterative solution but wonder if a more elegant solution could be found :
# Init my data.frame with random values
# Knowing my cumsum on "value" must be applied on the "group" column using the "ordering" column
random_values <- c(-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
values_probs <- c(0.7, 0.03, 0.03, 0.03, 0.03, 0.03, 0.03, 0.03, 0.03, 0.03, 0.03)
x <- data.frame(
group = rep(c("A", "B"), each = 10),
ordering = rep(1:10, 2),
value = sample(x = random_values, replace = T, prob = values_probs, size = 20)
)
# Create the "previous_conditional_sum" column
# Init the first row by group with the default starting value
starting_value <- 3
x <- x %>%
group_by(group) %>%
mutate(conditional_sum = NA_real_) %>%
mutate(previous_conditional_sum = case_when(
ordering == min(ordering) ~ starting_value,
T ~ NA_real_
)) %>%
as.data.frame()
# Here my "custom" sum function applying lower & upper limits
custom_sum <- function(a,b, lower_limit = 3, upper_limit = 15) {
x <- a+b
x <- min(x, upper_limit)
x <- max(x, lower_limit)
return(x)
}
# Iteratively sum using my custom function
for (i in 1:nrow(x)) {
# Init the new value
new_value <- custom_sum(x[i,"previous_conditional_sum",drop=T], x[i,"value",drop=T])
x[i,"conditional_sum"] <- new_value
# Set the previous_conditional_sum on next line if revelant
if (is.na(x[i+1, "previous_conditional_sum",drop=T]) & i+1<=nrow(x)) {
x[i+1, "previous_conditional_sum"] <- new_value
}
}