¿Suma acumulativa acumulada?

¿Cómo puedo hacer una sum acumulativa sobre un vector (como cumsum ), pero acotada para que la sum nunca pase por debajo de un límite inferior o por encima de un límite superior?

La función de cumsum estándar daría como resultado lo siguiente.

 foo <- c(100, -200, 400, 200) cumsum(foo) # [1] 100 -100 300 500 

Estoy buscando algo tan eficiente como la función base cumsum . Esperaría que el resultado se vea como el siguiente.

 cumsum.bounded(foo, lower.bound = 0, upper.bound = 500) # [1] 100 0 400 500 

Gracias

Como se mencionó en los comentarios, Rcpp es una buena forma de hacerlo.

cumsumBounded.cpp :

 #include  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; } 

Comstack y usa una nueva función:

 library(Rcpp) sourceCpp(file="cumsumBounded.cpp") foo < - c(100, -200, 400, 200) cumsumBounded(foo, 0, 500) # [1] 100 0 400 500 

Aquí hay un par de versiones R puros. No es probable que sea tan rápido como ir a C / C ++ pero uno de ellos podría ser lo suficientemente rápido para sus necesidades y sería más fácil de mantener:

 # 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 } 

Es posible que sea necesario mejorar ligeramente si x tiene una longitud de 0 o 1, dependiendo de qué tan estrictos sean los requisitos.

Supongo que esto podría funcionar.

 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; }')