我有具有数值的向量。例如:
inVector <- c(2, -10, 5, 34, 7)
我需要对此进行转换,以便在遇到负面元素时,该负面元素与后续元素相加,直到将总和变为正数的元素:
outVector <- c(2, 0, 0, 29, 7)
将负元素设为零,以便保留总和。所以元素2和3将为零,第四个元素等于29 = -10 + 5 + 34.我尝试了这样的for循环解决方案:
outVector <- numeric(length = length(inVector))
for(i in 1:length(inVector)) {
outVector <- inVector
outVector[i] <- ifelse(outVector[i] < 0, 0, outVector[i])
outVector[i + 1] <- ifelse(outVector[i] == 0, sum(inVector[i:(i+1)]), outVector[i + 1])
outVector <- outVector[1:length(inVector)]
}
但那并没有奏效。但是,我最感兴趣的是一个在dplyr管道中工作的解决方案。
答案 0 :(得分:6)
如果我们想要优化,我们可以使用更高效的Reduce
函数迭代向量:
#Help function
zeroElement <- function(vec) {
r <- Reduce(function(x,y) if(x >= 0) y else sum(x,y), vec, acc=TRUE)
r[r < 0] <- 0
return(r)
}
#Use function
zeroElement(x)
#[1] 2 0 0 29 7
速度测试:快25%:
t3 <- MakeNonNeg(BigVec)
t4 <- zeroElement(BigVec)
all.equal(t3, t4)
#[1] TRUE
library(microbenchmark)
microbenchmark(
makeNonNeg = MakeNonNeg(BigVec),
zeroElement = zeroElement(BigVec),
times=10)
# Unit: seconds
# expr min lq mean median uq max neval cld
# makeNonNeg 2.047484 2.099289 2.195988 2.111135 2.248381 2.531009 10 b
# zeroElement 1.529257 1.580789 1.666000 1.664855 1.725528 1.837825 10 a
添加会话信息以进行比较:
sessionInfo()
R version 3.3.0 (2016-05-03)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows >= 8 x64 (build 9200)
答案 1 :(得分:5)
试试这个:
MakeNonNeg <- function(v) {
size <- length(v)
myOut <- as.numeric(v)
if (size > 1L) {
for (i in 1:(size-1L)) {
if (myOut[i] >= 0) {next}
myOut[i+1L] <- myOut[i]+myOut[i+1L]
myOut[i] <- 0
}
}
myOut
}
MakeNonNeg(inVector)
[1] 2 0 0 29 7
以下是一个更具异国情调的例子:
set.seed(4242)
BigVec <- sample(-40000:100000, 100000, replace = TRUE)
gmp::sum.bigz(BigVec)
Big Integer ('bigz') :
[1] 2997861106
t3 <- MakeNonNeg(BigVec)
gmp::sum.bigz(t3)
Big Integer ('bigz') :
[1] 2997861106
BigVec[1:20]
[1] 98056 8680 -7814 53620 58390 90832 74970 -16392 52648 83779 -17229 38484 -36589 75156 71200 95968 -11599 57705
[19] 19209 -21596
t3[1:20]
[1] 98056 8680 0 45806 58390 90832 74970 0 36256 83779 0 21255 0 38567 71200 95968 0 46106 19209 0
这是我的系统信息:
sessionInfo()
R version 3.3.0 (2016-05-03)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 7 x64 (build 7601) Service Pack 1
以下是禁用JIT的两个功能的时间安排。
microbenchmark(
makeNonNeg = MakeNonNeg(BigVec),
zeroElement = zeroElement(BigVec),
times=10)
Unit: milliseconds
expr min lq mean median uq max neval
makeNonNeg 254.1255 255.8430 267.9527 258.6369 277.0222 303.6516 10
zeroElement 152.0358 164.7988 175.3191 166.4948 198.3855 209.8739 10
启用JIT
后,我们会为makeNonNeg
获得更多不同的结果。但是,zeroElement
的结果不会发生太大的变化(我认为,因为Reduce
是函数的主要部分并且它已经是字节编码,所以没有太多空间改进)。
library(compiler)
enableJIT(3)
[1] 0
microbenchmark(
makeNonNeg = MakeNonNeg(BigVec),
zeroElement = zeroElement(BigVec),
times=10)
Unit: milliseconds
expr min lq mean median uq max neval
makeNonNeg 11.20514 11.55366 12.76953 11.84655 12.20554 20.60036 10
zeroElement 144.15123 149.33591 163.66421 157.34711 176.20139 198.57268 10
因此,如果禁用JIT
,则zeroElement
的速度提高约50%,启用JIT
后,MakeNonNeg
的速度提高约13倍。