fma*_*ark 1 performance loops idioms r vectorization
可能重复:
使用先前的非NA值在向量中填充NA?
是否有一种惯用的方法可以在R向量中"向下"复制单元格值?通过"复制",我的意思是用最接近的先前非NA值替换NA.
虽然我可以使用for循环非常简单地执行此操作,但它运行速度非常慢.关于如何矢量化的任何建议将不胜感激.
# Test code
# Set up test data
len <- 1000000
data <- rep(c(1, rep(NA, 9)), len %/% 10) * rep(1:(len %/% 10), each=10)
head(data, n=25)
tail(data, n=25)
# Time naive method
system.time({
data.clean <- data;
for (i in 2:length(data.clean)){
if(is.na(data.clean[i])) data.clean[i] <- data.clean[i-1]
}
})
# Print results
head(data.clean, n=25)
tail(data.clean, n=25)
Run Code Online (Sandbox Code Playgroud)
试运行结果:
> # Set up test data
> len <- 1000000
> data <- rep(c(1, rep(NA, 9)), len %/% 10) * rep(1:(len %/% 10), each=10)
> head(data, n=25)
[1] 1 NA NA NA NA NA NA NA NA NA 2 NA NA NA NA NA NA NA NA NA 3 NA NA NA NA
> tail(data, n=25)
[1] NA NA NA NA NA 99999 NA NA NA NA
[11] NA NA NA NA NA 100000 NA NA NA NA
[21] NA NA NA NA NA
>
> # Time naive method
> system.time({
+ data.clean <- data;
+ for (i in 2:length(data.clean)){
+ if(is.na(data.clean[i])) data.clean[i] <- data.clean[i-1]
+ }
+ })
user system elapsed
3.09 0.00 3.09
>
> # Print results
> head(data.clean, n=25)
[1] 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3
> tail(data.clean, n=25)
[1] 99998 99998 99998 99998 99998 99999 99999 99999 99999 99999
[11] 99999 99999 99999 99999 99999 100000 100000 100000 100000 100000
[21] 100000 100000 100000 100000 100000
>
Run Code Online (Sandbox Code Playgroud)
我不知道惯用语,但在这里我们识别非NA值(idx),以及最后一个非NA值的索引(cumsum(idx))
f1 <- function(x) {
idx <- !is.na(x)
x[idx][cumsum(idx)]
}
Run Code Online (Sandbox Code Playgroud)
这似乎比na.locf示例数据快约6倍.它na.locf默认情况下会降低领先的NA ,所以
f2 <- function(x, na.rm=TRUE) {
idx <- !is.na(x)
cidx <- cumsum(idx)
if (!na.rm)
cidx[cidx==0] <- NA_integer_
x[idx][cidx]
}
Run Code Online (Sandbox Code Playgroud)
这似乎增加了大约30%的时间na.rm=FALSE.大概na.locf有其他优点,捕获更多的角落情况,并允许填补而不是下降(cumsum无论如何这是一个有趣的运动在世界上).还有一点很清楚,我们正在做可能大数据的至少五个分配- idx(实际上,我们计算is.na()它的补)cumsum(idx),x[idx]以及x[idx][cumsum(idx)]-所以有进一步改进的余地,比如,在C