惯用的方式在R矢量复制单元的值“向下” [复制](Idiomatic way to copy cel

2019-09-29 12:47发布

可能重复:
填充在使用现有非NA值的向量的NA?

有没有在R载体复制单元格值“向下”的惯用方式是什么? 通过“复制下来”,我指的是最接近先前的非NA值替换来港定居。

虽然我可以用一个做到这一点很简单的for循环,它运行速度非常慢。 如何vectorise这个任何意见,将不胜感激。

# 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)

试运行的结果:

> # 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
> 

Answer 1:

使用zoo::na.locf

包装你的代码功能f (包括返回data.clean末):

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


Answer 2:

我不知道地道的,但在这里,我们确定了非NA值( idx ),以及最后的非NA值的指数( cumsum(idx)

f1 <- function(x) {
    idx <- !is.na(x)
    x[idx][cumsum(idx)]
}

这似乎是比快约6倍na.locf对于示例数据。 它丢弃领先NA的像na.locf (默认设置),所以

f2 <- function(x, na.rm=TRUE) {
    idx <- !is.na(x)
    cidx <- cumsum(idx)
    if (!na.rm)
        cidx[cidx==0] <- NA_integer_
    x[idx][cidx]
}

这似乎加上约30%的时候, na.rm=FALSE 。 想必na.locf具有其他优点,获取更多的极端情况,并允许填满,而不是向下的(这是一个有趣的运动在cumsum世界,反正)。 还有一点很清楚,我们正在做可能大数据的至少五个分配- idx (实际上,我们计算is.na()和它的补), cumsum(idx) x[idx]x[idx][cumsum(idx)] -所以有进一步改进的余地,比如,在C



文章来源: Idiomatic way to copy cell values “down” in an R vector [duplicate]