在R向量中“向下”复制单元格值的惯用方法[重复]
Posted
技术标签:
【中文标题】在R向量中“向下”复制单元格值的惯用方法[重复]【英文标题】:Idiomatic way to copy cell values "down" in an R vector [duplicate] 【发布时间】:2013-01-05 03:52:45 【问题描述】:可能重复:Populate NAs in a vector using prior non-NA values?
是否有一种惯用的方法可以在 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)
试运行结果:
> # 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
>
【问题讨论】:
***.com/questions/9023072/… 【参考方案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
【讨论】:
【参考方案2】:我不知道惯用语,但这里我们识别非 NA 值 (idx
),以及最后一个非 NA 值的索引 (cumsum(idx)
)
f1 <- function(x)
idx <- !is.na(x)
x[idx][cumsum(idx)]
对于示例数据,这似乎比 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]
na.rm=FALSE
似乎增加了大约 30% 的时间。大概na.locf
有其他优点,捕获更多的极端情况并允许填充而不是向下填充(无论如何,这在cumsum
世界中是一个有趣的练习)。同样清楚的是,我们至少分配了五次可能的大数据——idx
(实际上,我们计算了is.na()
,它是补数)、cumsum(idx)
、x[idx]
和x[idx][cumsum(idx)]
——所以有有进一步改进的空间,例如在 C
【讨论】:
我称之为惯用语。很不错。在我的系统上比 na.locf 快 7 倍。以上是关于在R向量中“向下”复制单元格值的惯用方法[重复]的主要内容,如果未能解决你的问题,请参考以下文章