How to do a running calculation across vectors in R?

I created this data frame:

Count <- c(1:10)
Give <- c(0,0,5,0,0,5,0,5,0,5)
X <- c(rep(0,10))
Y <- c(rep(0,10))
Z <- c(rep(0,10))

X_Target <- 5
Y_Target <- 10
Z_Target <- 5

Basically I have 3 vectors (X,Y,Z) and a target for each one of them. I want to have a new calculation for X,Y and Z that based on the vector Give. Once the number on Give is bigger than 0 then it's need to be added to Vector X until it equel to X_Target. Then - the calcultion need to move to the next vector (Y) and do the same, and then to next vector...

The output should be like the following:

   Count Give X Y  Z
     1    0   0 0  0
     2    0   0 0  0
     3    5   5 0  0
     4    0   5 0  0
     5    0   5 0  0
     6    5   5 5  0
     7    0   5 5  0
     8    5   5 10 0
     9    0   5 10 0
    10    5   5 10 5

In this example I have only 3 vectors but please keep in mind that I'll have at least 60 vectors so I need it to be automatic as it can.

Hope I manage to explain myself :slight_smile: Thanks!

Here is a version with just the three columns:

Count <- c(1:10)
Give <- c(0,0,5,0,0,5,0,5,0,5)
X <- c(rep(0,10))
Y <- c(rep(0,10))
Z <- c(rep(0,10))

X_Target <- 5
Y_Target <- 10
Z_Target <- 5


df <- data.frame(Count,
                 Give,
                 Given = cumsum(Give))


df$X <- pmin(df$Given, X_Target)
df$Y <- pmin(df$Given - df$X, Y_Target)
df$Z <- pmin(df$Given - df$X - df$Y, Z_Target)


df
#>    Count Give Given X  Y Z
#> 1      1    0     0 0  0 0
#> 2      2    0     0 0  0 0
#> 3      3    5     5 5  0 0
#> 4      4    0     5 5  0 0
#> 5      5    0     5 5  0 0
#> 6      6    5    10 5  5 0
#> 7      7    0    10 5  5 0
#> 8      8    5    15 5 10 0
#> 9      9    0    15 5 10 0
#> 10    10    5    20 5 10 5

Created on 2020-12-08 by the reprex package (v0.3.0)

I'm not sure how to generalize to arbitrary columns. The easiest would be with a for loop, something like that (with probably quite a bit of thinking required for correct initialization etc):

Targets <- list(X=5,Y=10,Z=5)

for(i in seq_along(Targets)){
  df[[names(Targets[i])]] <- pmin(df$Given - df$sum_of_previous_targets, Targets[[i]])
  df$sum_of_previous_targets <- df$sum_of_previous_targets + df[[names(Targets[i])]]
}

I don't see how to easily use *apply() or map_*() since the result of each column depends on the previous columns, that means you would need to expand some big combination vector to get the equivalent of sum_of_previous_targets .

heres an alternative

Count <- c(1:10)
Give <- c(0,0,5,0,0,5,0,5,0,5)
X <- c(rep(0,10))
Y <- c(rep(0,10))
Z <- c(rep(0,10))

veclist <- list(X=X,Y=Y,Z=Z)
X_Target <- 5
Y_Target <- 10
Z_Target <- 5

tlist <- list(X_Target,Y_Target,Z_Target)

level <-1


for (i in seq_along(Give)){
  
  m <- max(veclist[[level]])

  if(m>=tlist[[level]]){

    level<-level+1
    #fill the previous level to the end
    if(level>=2){
      ilg <- i:length(Give)
      veclist[[level-1]][ilg] <- rep(veclist[[level-1]][[i-1]],length(ilg))
    } 
  }
  veclist[[level]][[i]] <- Give[[i]] + if(i>1) veclist[[level]][[i-1]] else 0
}

data.frame(veclist)

This topic was automatically closed 21 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.