2014-01-21 2 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++하지만 그들 중 하나에 갈만큼 빠르게 될 가능성 및 유지 관리가 쉬울 것하지 :

x 길이가 0이있는 경우이 약간 개선해야 할 수있다
# 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 
} 

또는 요구 사항이 얼마나 엄격한 지에 따라 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; 
    }')