Bounded cumulative sum?

后端 未结 3 1626
野趣味
野趣味 2020-12-03 15:37

How can I do a cumulative sum over a vector (like cumsum), but bounded so that the summation never goes below a lower bound or above an upper bound?

T

相关标签:
3条回答
  • 2020-12-03 15:45

    I suppose this might work.

    library ("Rcpp")
    
    cumsum.bounded <- cppFunction(
        'NumericVector cumsum_bounded (NumericVector x, const double lower, const double upper) {
    
            double acc = 0;
            NumericVector result(x.size());
    
            for(int i = 0; i < x.size(); i++) {
                acc += x[i];
    
                if (acc < lower) acc = lower;
                if (acc > upper) acc = upper;
    
                result[i] = acc;
            }
    
            return result;
        }')
    
    0 讨论(0)
  • 2020-12-03 15:50

    Here are a couple of pure R versions. Not likely to be as fast as going to C/C++ but one of them might be fast enough for your needs and would be easier to maintain:

    # 1 Reduce
    cumsum.bounded <- function(x, lower.bound = 0, upper.bound = 500) {
        bsum <- function(x, y) min(upper.bound, max(lower.bound, x+y))
        if (length(x) > 1) Reduce(bsum, x, acc = TRUE) else x
    }
    
    # 2 for loop
    cumsum.bounded2 <- function(x, lower.bound = 0, upper.bound = 500) {
       if (length(x) > 1) 
          for(i in  2:length(x)) x[i] <- min(upper.bound, max(lower.bound, x[i] + x[i-1]))
       x
    }
    

    These may be need to be enhanced slightly if x has length 0 or 1 depending on how strict the requirements are.

    0 讨论(0)
  • 2020-12-03 16:05

    As mentioned in the comments, Rcpp is a good way to go.

    cumsumBounded.cpp:

    #include <Rcpp.h>
    using namespace Rcpp;
    // [[Rcpp::export]]                                                             
    NumericVector cumsumBounded(NumericVector x, double low, double high) {
      NumericVector res(x.size());
      double acc = 0;
      for (int i=0; i < x.size(); ++i) {
        acc += x[i];
        if (acc < low)  acc = low;
        else if (acc > high)  acc = high;
        res[i] = acc;
      }
      return res;
    }
    

    Compile and use new function:

    library(Rcpp)
    sourceCpp(file="cumsumBounded.cpp")
    foo <- c(100, -200, 400, 200)
    cumsumBounded(foo, 0, 500)
    # [1] 100   0 400 500
    
    0 讨论(0)
提交回复
热议问题