仅将时间序列中的 NA 填充到有限的数量
Posted
技术标签:
【中文标题】仅将时间序列中的 NA 填充到有限的数量【英文标题】:Fill NA in a time series only to a limited number 【发布时间】:2014-11-14 10:07:17 【问题描述】:有没有一种方法可以将NA
s 填充到zoo
或xts
对象中,并转发有限数量的NA
s。换句话说,就像将NA
s 填充到最多 3 个连续的NA
s,然后将NA
s 从第 4 个值开始保持到有效数字为止。
类似的东西。
library(zoo)
x <- zoo(1:20, Sys.Date() + 1:20)
x[c(2:4, 6:10, 13:18)] <- NA
x
2014-09-20 2014-09-21 2014-09-22 2014-09-23 2014-09-24 2014-09-25 2014-09-26
1 NA NA NA 5 NA NA
2014-09-27 2014-09-28 2014-09-29 2014-09-30 2014-10-01 2014-10-02 2014-10-03
NA NA NA 11 12 NA NA
2014-10-04 2014-10-05 2014-10-06 2014-10-07 2014-10-08 2014-10-09
NA NA NA NA 19 20
所需的输出,将是变量 n = 3 的东西
2014-09-20 2014-09-21 2014-09-22 2014-09-23 2014-09-24 2014-09-25 2014-09-26
1 1 1 1 5 5 5
2014-09-27 2014-09-28 2014-09-29 2014-09-30 2014-10-01 2014-10-02 2014-10-03
5 NA NA 11 12 12 12
2014-10-04 2014-10-05 2014-10-06 2014-10-07 2014-10-08 2014-10-09
12 NA NA NA 19 20
我尝试了很多与na.locf(x, maxgap = 3)
等的组合,但没有取得多大成功。我可以创建一个循环来获得所需的输出,我想知道是否有矢量化的方式来实现这一点。
fillInTheBlanks <- function(v, n=3)
result <- v
counter0 <- 1
for(i in 2:length(v))
value <- v[i]
if (is.na(value))
if (counter0 > n)
result[i] <- v[i]
else
result[i] <- result[i-1]
counter0 <- counter0 + 1
else
result[i] <- v[i]
counter0 <- 1
return(result)
谢谢
【问题讨论】:
添加一些用例场景,当我们有一个 qtrly 数据并且我们知道未来 3 个月的数据是好的,并且可能最多再多 3 个月,但任何超出可接受的范围时限制应该使数据真正不适用,并且不应该填充它直到无穷大的场景。 这里有一些其他选择:Replace NA with previous value with limit 【参考方案1】:这是另一种方式:
l <- cumsum(! is.na(x))
c(NA, x[! is.na(x)])[replace(l, ave(l, l, FUN=seq_along) > 4, 0) + 1]
# [1] 1 1 1 1 5 5 5 5 NA NA 11 12 12 12 12 NA NA NA 19 20
编辑:我之前的回答要求x
没有重复项。目前的答案没有。
基准测试
x <- rep(x, length.out=1e4)
plourde <- function(x)
l <- cumsum(! is.na(x))
c(NA, x[! is.na(x)])[replace(l, ave(l, l, FUN=seq_along) > 4, 0) + 1]
agstudy <- function(x)
unlist(sapply(split(coredata(x),cumsum(!is.na(x))),
function(sx)
if(length(sx)>3)
sx[2:4] <- rep(sx[1],3)
else sx <- rep(sx[1],length(sx))
sx
))
microbenchmark(plourde(x), agstudy(x))
# Unit: milliseconds
# expr min lq median uq max neval
# plourde(x) 5.30 5.591 6.409 6.774 57.13 100
# agstudy(x) 16.04 16.249 16.454 17.516 20.64 100
【讨论】:
【参考方案2】:还有一个想法,除非我错过了什么,否则似乎是有效的:
na_locf_until = function(x, n = 3)
wnn = which(!is.na(x))
inds = sort(c(wnn, (wnn + n+1)[which((wnn + n+1) < c(wnn[-1], length(x)))]))
c(rep(NA, wnn[1] - 1),
as.vector(x)[rep(inds, c(diff(inds), length(x) - inds[length(inds)] + 1))])
na_locf_until(x)
#[1] 1 1 1 1 5 5 5 5 NA NA 11 12 12 12 12 NA NA NA 19 20
【讨论】:
【参考方案3】:不使用na.locf
,但想法是按一组非缺失值拆分您的 xts,然后为每个组仅用第一个值替换 3 个第一个值(在非缺失值之后)。它是一个循环,但由于它只应用于 group ,它应该比所有值的简单循环更快。
zz <-
unlist(sapply(split(coredata(x),cumsum(!is.na(x))),
function(sx)
if(length(sx)>3)
sx[2:4] <- rep(sx[1],3)
else sx <- rep(sx[1],length(sx))
sx
))
## create the zoo object since , the latter algorithm is applied only to the values
zoo(zz,index(x))
2014-09-20 2014-09-21 2014-09-22 2014-09-23 2014-09-24 2014-09-25 2014-09-26 2014-09-27 2014-09-28 2014-09-29 2014-09-30 2014-10-01 2014-10-02
1 1 1 1 5 5 5 5 NA NA 11 12 12
2014-10-03 2014-10-04 2014-10-05 2014-10-06 2014-10-07 2014-10-08 2014-10-09
12 12 NA NA NA 19 20
【讨论】:
【参考方案4】:在data.table
中实现这一点的最简洁方法可能是使用连接语法:
na.omit(dt)[dt, on = .(date), roll = +3, .(date, x_filled = x, x = i.x)]
date x_filled x
1: 2019-02-14 1 1
2: 2019-02-15 1 NA
3: 2019-02-16 1 NA
4: 2019-02-17 1 NA
5: 2019-02-18 5 5
6: 2019-02-19 5 NA
7: 2019-02-20 5 NA
8: 2019-02-21 5 NA
9: 2019-02-22 NA NA
10: 2019-02-23 NA NA
11: 2019-02-24 11 11
12: 2019-02-25 12 12
13: 2019-02-26 12 NA
14: 2019-02-27 12 NA
15: 2019-02-28 12 NA
16: 2019-03-01 NA NA
17: 2019-03-02 NA NA
18: 2019-03-03 NA NA
19: 2019-03-04 19 19
20: 2019-03-05 20 20
*此解决方案取决于日期列并且是连续的
【讨论】:
由于技术和逻辑不同,因此作为单独的答案发布。【参考方案5】:在data.table
中玩耍,得到了这个 hacky 解决方案:
np1 <- 3 + 1
dt[,
x_filled := x[c(rep(1, min(np1, .N)), rep(NA, max(0, .N - np1)))],
by = cumsum(!is.na(x))]
# Or slightly simplified:
dt[,
x_filled := ifelse(rowid(x) < 4, x[1], x[NA]),
by = cumsum(!is.na(x))]
> dt
date x x_filled
1: 2019-02-14 1 1
2: 2019-02-15 NA 1
3: 2019-02-16 NA 1
4: 2019-02-17 NA 1
5: 2019-02-18 5 5
6: 2019-02-19 NA 5
7: 2019-02-20 NA 5
8: 2019-02-21 NA 5
9: 2019-02-22 NA NA
10: 2019-02-23 NA NA
11: 2019-02-24 11 11
12: 2019-02-25 12 12
13: 2019-02-26 NA 12
14: 2019-02-27 NA 12
15: 2019-02-28 NA 12
16: 2019-03-01 NA NA
17: 2019-03-02 NA NA
18: 2019-03-03 NA NA
19: 2019-03-04 19 19
20: 2019-03-05 20 20
我们基于这样一个事实,即用NA
对向量进行子集化会返回NA
。
数据/包
library(zoo)
library(data.table)
x <- zoo(1:20, Sys.Date() + 1:20)
x[c(2:4, 6:10, 13:18)] <- NA
dt <- data.table(date = index(x), x = as.integer(x))
【讨论】:
以上是关于仅将时间序列中的 NA 填充到有限的数量的主要内容,如果未能解决你的问题,请参考以下文章
在数组中填充有限数量的项目,但保持数组长度 - mongoose
如何填充(自动填充)值,例如使用 R 中的 data.table 将 NA 替换为组中的第一个值?