我有带有数值的向量。例如:

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 管道的解决方案。

最佳答案

试试这个:

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 倍。

关于R:数值向量的条件求和,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/39103071/

10-12 17:54