Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vector with various IFs, adding up and counting down

I have one vector

x <- c(5,2,-4,-6,-2,1,4,2,-3,-6,-1,8,9,5,-6,-11)

Now, a vector y needs to accumulate if vector x is negative and the opposite when positive until back to zero:

y <- c(0,0,-4,-10,-12,-11,-7,-5,-8,-14,-15,-7,0,0,-6,-17)

Here are the conditions to be respected:

  • The cumulative sum of negative and positive values as long as the sum is less than 0

  • If the sum is positive, the cumulative sum is stopped until the following negative values are reached.

  • When the sum becomes positive, the printed value is 0.

Thanks for help!

like image 229
Sebastien_H Avatar asked Mar 07 '26 12:03

Sebastien_H


2 Answers

I think that this calculation is not trivial to vectorise because the elements depend in a non-trivial way on previous elements, so the best approach might simply be to use a loop:

x <- c(5,2,-4,-6,-2,1,4,2,-3,-6,-1,8,9,5,-6,-11)

y <- pmin(x,0) # gives us the first element correctly, and the correct vector length
for (i in seq_along(x[-1])) y[i+1] <- pmin(y[i] + x[i+1], 0)

y

# [1]   0   0  -4 -10 -12 -11  -7  -5  -8 -14 -15  -7   0   0  -6 -17
like image 53
Miff Avatar answered Mar 09 '26 00:03

Miff


x <- c(5,2,-4,-6,-2,1,4,2,-3,-6,-1,8,9,5,-6,-11)

for (i in seq_along(x)) { x[i] = ifelse(sum(x[(i-1):i]) > 0, 0, sum(x[(i-1):i])) }

x

# [1]   0   0  -4 -10 -12 -11  -7  -5  -8 -14 -15  -7   0   0  -6 -17

Another approach is using Reduce like this:

Reduce(function(u, v) ifelse(sum(c(u, v)) > 0, 0, sum(c(u, v))), x, accumulate = T, init = x[1])[-1]

#  [1]   0   0  -4 -10 -12 -11  -7  -5  -8 -14 -15  -7   0   0  -6 -17

If you want to apply that process to each column you can use this example:

# example dataset
df = data.frame(x = c(5,2,-4,-6,-2,1,4,2,-3,-6,-1,8,9,5,-6,-11),
                y = c(5,2,-4,-6,-2,1,4,2,-3,-6,-1,8,9,5,-6,-11),
                z = c(5,2,-4,-6,-2,1,4,2,-3,-6,-1,8,9,5,-6,-11))

# function to update columns
UpdateColumn = function(x) { 
  for (i in seq_along(x)) { x[i] = ifelse(sum(x[(i-1):i]) > 0, 0, sum(x[(i-1):i])) }
  x
                            }

# apply function to each column
# save as data frame
data.frame(sapply(df, UpdateColumn))

#      x   y   z
# 1    0   0   0
# 2    0   0   0
# 3   -4  -4  -4
# 4  -10 -10 -10
# 5  -12 -12 -12
# 6  -11 -11 -11
# 7   -7  -7  -7
# 8   -5  -5  -5
# 9   -8  -8  -8
# 10 -14 -14 -14
# 11 -15 -15 -15
# 12  -7  -7  -7
# 13   0   0   0
# 14   0   0   0
# 15  -6  -6  -6
# 16 -17 -17 -17
like image 20
AntoniosK Avatar answered Mar 09 '26 02:03

AntoniosK



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!