R中条件的累积和

时间:2016-12-06 13:15:12

标签: r

说我有

a <- c(0, 22, 0, 2, 0, 0, 20, 20, 20, 0, 0)

我想做累积总和,我对5中的每个值减去a,然后添加前一个值。

但是,如果a变得小于0,我还希望将cumsum设为0a变得大于40 },为cumsum 40

所以,我想得到

(0, 17, 12, 9, 4, 0, 15, 30, 40, 35, 30)

有人可以帮忙吗?我现在已经尝试了很多东西了几个小时!

@Holger,这种方法并不总是有效。 因此,如果我添加了几个额外的零,它就没有合适的解决方案

a <- c(0, 22, 0, 2, 0, 0, 0, 0, 20, 20, 20, 0, 0)

给出

 0 17 12  9  4  0  1  7 22 37 52 47 42

4 个答案:

答案 0 :(得分:3)

以下是一些替代方案:

1)循环创建一个这样的单行循环:

b <- a; for(i in seq_along(b)[-1]) b[i] <- min(40, max(0, a[i] - 5 + b[i-1]))
b
## [1]  0 17 12  9  4  0 15 30 40 35 30

2)减少

f <- function(b, a) min(40, max(0, a - 5 + b))
Reduce(f, a, acc = TRUE)
## [1]  0 17 12  9  4  0 15 30 40 35 30

3)递归这种递归解决方案仅限于不太长的输入。

rec <- function(a) {
   n <- length(a)
   if (n <= 1) a
   else {
     rec.hd <- Recall(a[-n])
     c(rec.hd, min(40, max(0, rec.hd[n-1] + a[n] - 5)))
   }
}
rec(a)
## [1]  0 17 12  9  4  0 15 30 40 35 30

答案 1 :(得分:1)

尝试

cumsum_up_low <- function(a, d=5, up=40, low=0 ){
  out = rep(0, length(a))
  out[1] = a[1]*(a[1]>=0 && a[1]<=40) + 0*(a[1]<0) + 40*(a[1] > 40)
  for(i in 2:length(a)){
    if(out[i-1] + a[i] - d > low && out[i-1] + a[i] - d < up){
      out[i] = out[i-1] + a[i] - d
    } else if(out[i-1] + a[i] - d <= low){
      out[i] = 0          
    } else out[i] = 40
  }
  out
}

cumsum_up_low(a, d=5, up=40, low=0)
# [1]  0 17 12  9  4  0 15 30 40 35 30

对于长载体

a <- sample(a, 1e6, TRUE)
system.time(cumsum_up_low(a))
#   user  system elapsed 
#   3.59    0.00    3.59 
library(compiler)
cumsum_up_low_compiled <- cmpfun(cumsum_up_low)
system.time(cumsum_up_low_compiled(a))
#   user  system elapsed 
#   0.28    0.00    0.28 

对于一个非常长的载体

library(Rcpp)
cppFunction('
NumericVector cumsum_up_low_cpp(NumericVector a, double d, double up, double low) {
  NumericVector out(a.size());
  out[0] = a[0];
  for(int i=1; i<a.size(); i++){
    if(out[i-1] + a[i] - d > low & out[i-1] + a[i] - d < up){
      out[i] = out[i-1] + a[i] - d;
    } else if(out[i-1] + a[i] - d <= low){
      out[i] = 0;          
    } else out[i] = 40;
  }
  return out;
}')

a <- sample(a, 5e6, replace = TRUE)
system.time(cumsum_up_low_compiled(a, d=5, up=40, low=0))
#   user  system elapsed 
#   1.45    0.00    1.46 
system.time(cumsum_up_low_cpp(a, d=5, up=40, low=0))
#   user  system elapsed 
#   0.04    0.02    0.05 

答案 2 :(得分:1)

您可以使用Reduce获取累计总和,并将其与maxminpminpmax结合使用以获得界限。

目前还不清楚是否要在累积总和中使用0和40,或者是否要在之后绑定变量。下面,我提供了两种可能性。

总和中的界限:

Reduce(function(x, y) min(max(x + y - 5, 0), 40), a, 0, accumulate=TRUE)
[1]  0  0 17 12  9  4  0 15 30 40 35 30

总和后绑定

pmin(pmax(Reduce(function(x, y) x + y - 5, a, 0, accumulate=TRUE), 0), 40)
[1]  0  0 12  7  4  0  0  9 24 39 34 29

答案 3 :(得分:0)

这绝对不是执行此操作的有效方式,但最容易理解:

a <- c(0, 22, 0, 2, 0, 0, 20, 20, 20, 0, 0)

## Initialize another vector just like a
c <- a


## Do it easy-to-understand'ly in a for loop:
for (i in seq_along(a)){
  b <- a[i]
  if (i>1) {
    b <- b+c[i-1]
    b <- b-5
  } 
  if (b<0) b <- 0
  if (b>40) b <- 40
  c[i] <- b
  print(c[i])
}

尝试找出每个部分,如果需要帮助,请知道!