Performance “复制单元格值的惯用方法”;“向下”;在R向量中
可能重复:Performance “复制单元格值的惯用方法”;“向下”;在R向量中,performance,r,loops,vectorization,idioms,Performance,R,Loops,Vectorization,Idioms,可能重复: 有没有一种惯用的方法在R向量中“向下”复制单元格值?“向下复制”是指用最接近的先前非NA值替换NAs 虽然我可以用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)
有没有一种惯用的方法在R向量中“向下”复制单元格值?“向下复制”是指用最接近的先前非NA值替换NAs 虽然我可以用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)
#测试代码
#设置测试数据
伦恩
>#时间朴素方法
>系统时间({
+data.clean#打印结果
>压头(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
>尾部(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
>
使用zoo::na.locf
在函数f
中包装代码(包括返回数据。最后清理):
使用zoo::na.locf
在函数f
中包装代码(包括返回数据。最后清理):
我不知道惯用语,但这里我们确定了非NA值(idx
),以及最后一个非NA值的索引(cumsum(idx)
)
当na.rm=FALSE
时,这似乎增加了约30%的时间。想必na.locf
还有其他优点,可以捕获更多的角落案例,并允许填充而不是填充(无论如何,这在cumsum
世界中是一个有趣的练习)。很明显,我们至少分配了五个可能较大的数据--idx
(实际上,我们计算is.na()
及其补码),cumsum(idx)
,x[idx]
,以及x[idx][cumsum(idx)]
--因此还有进一步改进的余地,例如,在C中,我不知道惯用语,但这里我们确定了非NA值(idx
),以及最后一个非NA值的索引(cumsum(idx)
)
当na.rm=FALSE
时,这似乎增加了约30%的时间。想必na.locf
还有其他优点,可以捕获更多的角落案例,并允许填充而不是填充(无论如何,这在cumsum
世界中是一个有趣的练习)。很明显,我们至少分配了五个可能较大的数据--idx
(实际上,我们计算is.na()
及其补码),cumsum(idx)
,x[idx]
,以及x[idx][cumsum(idx)]
——因此还有进一步改进的余地,例如,在C中,我称之为惯用。非常好。比我的系统上的na.locf快7倍。我称之为惯用。非常好。比我的系统上的na.locf快7倍。
> # 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
>
library(rbenchmark)
library(zoo)
identical(f(data), na.locf(data))
## [1] TRUE
benchmark(f(data), na.locf(data), replications=10, columns=c("test", "elapsed", "relative"))
## test elapsed relative
## 1 f(data) 21.460 14.471
## 2 na.locf(data) 1.483 1.000
f1 <- function(x) {
idx <- !is.na(x)
x[idx][cumsum(idx)]
}
f2 <- function(x, na.rm=TRUE) {
idx <- !is.na(x)
cidx <- cumsum(idx)
if (!na.rm)
cidx[cidx==0] <- NA_integer_
x[idx][cidx]
}