说我有
a <- c(0, 22, 0, 2, 0, 0, 20, 20, 20, 0, 0)
我想做累积总和,我对5
中的每个值减去a
,然后添加前一个值。
但是,如果a
变得小于0
,我还希望将cumsum设为0
,a
变得大于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
答案 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
获取累计总和,并将其与max
和min
或pmin
和pmax
结合使用以获得界限。
目前还不清楚是否要在累积总和中使用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])
}
尝试找出每个部分,如果需要帮助,请知道!