【问题标题】:Bounded cumulative sum?有界累积和?
【发布时间】:2014-02-11 07:12:50
【问题描述】:

我怎样才能对一个向量(如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

谢谢

【问题讨论】:

  • 如果您正在寻找与基本 cumsum 函数一样高效的函数,则必须在 C 中实现它。
  • 根据自己的需要调整Rcpp的糖函数cumsum应该比较容易。据我所知,您只需要添加一个 if 语句。
  • @SvenHohenstein 或更可能是Rcpp 解决方案。

标签: r


【解决方案1】:

如 cmets 中所述,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

【讨论】:

    【解决方案2】:

    这里有几个纯 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,则这些可能需要稍微增强,具体取决于要求的严格程度。

    【讨论】:

    • 如果第一个元素突破界限,它们就会失败。 cumsum.bounded(c(-1,-1,3,4,5), 0, 10) =&gt; -1 0 3 7 10cumsum.bounded(c(20,-1,3,4,5), 0, 10) =&gt; 20 10 10 10 10
    • 存在一些问题,例如边缘情况是否真的是问题的一部分,或者问题是否是将总和保持在范围内,但如果需要,可以使用 cumsum.bounded(c(0, x), 0, 10)[-1] 轻松处理或者通过在函数中单独处理初始值。
    • 是的。我觉得还是值得注意的。我用它来计算某种偏好,其中我有一个匹配我的谓词的选择,如果不是,则为 -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;
        }')
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-01-23
      • 2021-07-04
      • 1970-01-01
      • 2019-02-15
      • 1970-01-01
      • 1970-01-01
      • 2022-10-21
      相关资源
      最近更新 更多