2014-01-21 83 views
9

如何對矢量(如cumsum)進行累加求和,但是有界,這樣總和不會低於下限或高於上限?有界的累積和?

標準cumsum函數將導致以下結果。

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

我正在尋找像基地cumsum函數那樣高效的東西。我期望輸出看起來如下所示。

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

感謝

+3

如果你在尋找一個和'cumsum'基函數一樣高效的函數,你必須在'C'中實現它。 –

+1

根據您的需要調整Rcpp的糖功能[cumsum](http://dirk.eddelbuettel.com/code/rcpp/html/cumsum_8h_source.html)應該相對容易。據我所知,你只需要添加一個if語句。 – Roland

+0

@SvenHohenstein或更可能是'Rcpp'解決方案。 –

回答

11

正如評論所說,Rcpp是一個很好的路要走。

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

編譯和使用新的功能:

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

這裏有幾個純的R版本。可能不會那麼快是因爲將C/C++,但他們中的一個可能是你需要有足夠的速度快,會更容易維護:

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

這些可以需要稍微如果x長度爲0增強或1取決於要求的嚴格程度。

3

我想這可能工作。

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