geo*_*try 28 r missing-data na
我正在寻找类似于包na.locf()
中的东西zoo
,但不是总是使用之前的非NA
值我想使用最接近的非NA
值.一些示例数据:
dat <- c(1, 3, NA, NA, 5, 7)
Run Code Online (Sandbox Code Playgroud)
替换NA
为na.locf
(3继续):
library(zoo)
na.locf(dat)
# 1 3 3 3 5 7
Run Code Online (Sandbox Code Playgroud)
并na.locf
用fromLast
组到TRUE
(5向后携带):
na.locf(dat, fromLast = TRUE)
# 1 3 5 5 5 7
Run Code Online (Sandbox Code Playgroud)
但我希望使用最接近的非NA
值.在我的例子中,这意味着3应该被转发到第一个NA
,而5应该被转发到第二个NA
:
1 3 3 5 5 7
Run Code Online (Sandbox Code Playgroud)
我有一个编码的解决方案,但想确保我没有重新发明轮子.有什么东西已经浮动了吗?
仅供参考,我目前的代码如下.也许如果不出意外,有人可以建议如何提高效率.我觉得我错过了一个明显的改进方法:
na.pos <- which(is.na(dat))
if (length(na.pos) == length(dat)) {
return(dat)
}
non.na.pos <- setdiff(seq_along(dat), na.pos)
nearest.non.na.pos <- sapply(na.pos, function(x) {
return(which.min(abs(non.na.pos - x)))
})
dat[na.pos] <- dat[non.na.pos[nearest.non.na.pos]]
Run Code Online (Sandbox Code Playgroud)
要回答以下smci的问题:
更新所以事实证明我们完全朝着不同的方向前进,但这仍然是一个有趣的讨论.谢谢大家!
flo*_*del 22
这是一个非常快的.它用于findInterval
查找NA
原始数据中每个位置应考虑的两个位置:
f1 <- function(dat) {
N <- length(dat)
na.pos <- which(is.na(dat))
if (length(na.pos) %in% c(0, N)) {
return(dat)
}
non.na.pos <- which(!is.na(dat))
intervals <- findInterval(na.pos, non.na.pos,
all.inside = TRUE)
left.pos <- non.na.pos[pmax(1, intervals)]
right.pos <- non.na.pos[pmin(N, intervals+1)]
left.dist <- na.pos - left.pos
right.dist <- right.pos - na.pos
dat[na.pos] <- ifelse(left.dist <= right.dist,
dat[left.pos], dat[right.pos])
return(dat)
}
Run Code Online (Sandbox Code Playgroud)
在这里我测试它:
# sample data, suggested by @JeffAllen
dat <- as.integer(runif(50000, min=0, max=10))
dat[dat==0] <- NA
# computation times
system.time(r0 <- f0(dat)) # your function
# user system elapsed
# 5.52 0.00 5.52
system.time(r1 <- f1(dat)) # this function
# user system elapsed
# 0.01 0.00 0.03
identical(r0, r1)
# [1] TRUE
Run Code Online (Sandbox Code Playgroud)
代码如下.最初的问题并没有完全明确,我曾要求做出这些澄清:
1 3 NA NA NA 5 7
?[不关心/离开]ifelse
如果S很大且行数和列数很大的数据帧解决方案.)[最坏情况S可能在病理上很大,因此不应使用递归]geoffjentry,你的解决方案你的瓶颈将是串行计算nearest.non.na.pos
和序列分配dat[na.pos] <- dat[non.na.pos[nearest.non.na.pos]]
对于长度G的大差距,我们真正需要计算的是第一个(G/2,向上舍入)项目从左边填充,从右边休息.(我可以发布一个答案,ifelse
但看起来很相似.)你的标准运行时,大O效率,临时内存使用或代码易读性?
Coupla可能的调整:
N <- length(dat)
一次if (length(na.pos) == 0)
跳过行,因为它没有NAif (length(na.pos) == length(dat)-1)
(稀少)情况下只有一个非NA条目,因此我们用它填充整行大纲解决方案
遗憾的是na.locf不适用于整个数据帧,你必须使用sapply,row-wise:
na.fill_from_nn <- function(x) {
row.na <- is.na(x)
fillFromLeft <- na.locf(x, na.rm=FALSE)
fillFromRight <- na.locf(x, fromLast=TRUE, na.rm=FALSE)
disagree <- rle(fillFromLeft!=fillFromRight)
for (loc in (disagree)) { ... resolve conflicts, row-wise }
}
sapply(dat, na.fill_from_nn)
Run Code Online (Sandbox Code Playgroud)
或者,因为正如你所说的那样,连续的NAs是罕见的,所以要快速和愚蠢ifelse
地从左边填充孤立的NA.这将以数据帧方式操作=>使公共情况快速.然后使用行方式for循环处理所有其他情况.(这会影响很长一段时间内中间元素的抢七,但你说你不在乎.)
小智 5
我喜欢所有严格的解决方案。虽然不是直接询问什么,但我发现这篇文章正在寻找一种用插值填充 NA 值的解决方案。审阅这篇文章后,我发现 na.fill 在一个zoo
对象(向量、因子或矩阵)上:
z <- c(1,2,3,4,5,6,NA,NA,NA,2,3,4,5,6,NA,NA,4,6,7,NA)
z1 <- zoo::na.fill(z, "extend")
Run Code Online (Sandbox Code Playgroud)
注意 NA 值的平滑过渡
round(z1, 0)
#> [1] 1 2 3 4 5 6 5 4 3 2 3 4 5 6 5 5 4 6 7 7
Run Code Online (Sandbox Code Playgroud)
也许这可以帮助