使用季节性循环插入时间序列中的缺失值

时间:2011-02-11 00:12:27

标签: r interpolation time-series

我有一个时间序列,我想要智能地插入缺失值。特定时间的价值受多日趋势以及其在日常周期中的位置的影响。

以下是myzoo

中缺少第十个观察的示例
start <- as.POSIXct("2010-01-01") 
freq <- as.difftime(6, units = "hours") 
dayvals <- (1:4)*10 
timevals <- c(3, 1, 2, 4) 
index <- seq(from = start, by = freq, length.out = 16)
obs <- (rep(dayvals, each = 4) + rep(timevals, times = 4))
myzoo <- zoo(obs, index)
myzoo[10] <- NA

如果我必须实现这个,我会在附近的日子使用某种近似加权平均值,或者将当天的值加到适合较大趋势的函数线上,但我希望已经存在一些适用于这种情况的包裹或功能?

编辑:略微修改代码以澄清我的问题。有na.*个方法可以从最近的邻居进行插值,但在这种情况下,它们无法识别缺失值是当天的最低值。也许解决方案是将数据重新整形为宽格式然后进行插值,但我不想完全忽略同一天的连续值。值得注意的是diff(myzoo, lag = 4)返回10的向量。解决方案可能有reshapena.splinediff.inv的某种组合,但我无法理解。

以下三种方法不起作用: enter image description here

EDIT2。使用以下代码生成图像。

myzoo <- zoo(obs, index)
myzoo[10] <- NA # knock out the missing point
plot(myzoo, type="o", pch=16) # plot solid line
points(na.approx(myzoo)[10], col = "red")
points(na.locf(myzoo)[10], col = "blue")
points(na.spline(myzoo)[10], col = "green")
myzoo[10] <- 31 # replace the missing point
lines(myzoo, type = "o", lty=3, pch=16) # dashed line over the gap
legend(x = "topleft", 
       legend = c("na.spline", "na.locf", "na.approx"), 
       col=c("green","blue","red"), pch = 1)

4 个答案:

答案 0 :(得分:17)

试试这个:

x <- ts(myzoo,f=4)
fit <- ts(rowSums(tsSmooth(StructTS(x))[,-2]))
tsp(fit) <- tsp(x)
plot(x)
lines(fit,col=2)

这个想法是使用时间序列的基本结构模型,使用卡尔曼滤波器处理缺失值。然后使用卡尔曼平滑来估计时间序列中的每个点,包括任何省略的点。

我必须将您的zoo对象转换为频率为4的ts对象才能使用StructTS。您可能希望再次将拟合值更改回动物园。

答案 1 :(得分:2)

在这种情况下,我认为你想在ARIMA模型中进行季节性修正。这里没有足够的日期来适应季节性模型,但这应该让你开始。

library(zoo)
start <- as.POSIXct("2010-01-01") 
freq <- as.difftime(6, units = "hours") 
dayvals <- (1:4)*10 
timevals <- c(3, 1, 2, 4) 
index <- seq(from = start, by = freq, length.out = 16)
obs <- (rep(dayvals, each = 4) + rep(timevals, times = 4))
myzoo <- myzoo.orig <- zoo(obs, index)
myzoo[10] <- NA

myzoo.fixed <- na.locf(myzoo)

myarima.resid <- arima(myzoo.fixed, order = c(3, 0, 3), seasonal = list(order = c(0, 0, 0), period = 4))$residuals
myzoo.reallyfixed <- myzoo.fixed
myzoo.reallyfixed[10] <- myzoo.fixed[10] + myarima.resid[10]

plot(myzoo.reallyfixed)
points(myzoo.orig)

在我的测试中,ARMA(3,3)非常接近,但这只是运气。使用较长的时间序列,您应该能够校准季节性校正,以便为您提供良好的预测。在信号和季节性修正的基础机制之前有一个良好的优先选择,以提高样本性能,这将是有益的。

答案 2 :(得分:2)

forecast::na.interp是一种很好的方法。来自documentation

  

对非季节性系列使用线性插值,使用季节性系列进行周期性stl分解以替换缺失值。

library(forecast)
fit <- na.interp(myzoo)
fit[10]  # 32.5, vs. 31.0 actual and 32.0 from Rob Hyndman's answer

This paper根据实时序列评估几种插值方法,并发现na.interp既准确又高效:

  

从本文测试的R实现中,来自预测包的na.interp和来自动物园包的na.StructTS显示了最佳的整体结果。

     

na.interp功能也没有那么慢   na.approx [最快的方法],所以黄土分解在计算时间方面似乎不是很苛刻。

另外值得注意的是,Rob Hyndman在提供他对这个问题的回答之后编写了forecast包,并包含了na.interpna.interp可能是这种方法的改进,即使它在这种情况下表现更差(可能是由于在StructTS中指定了句点,其中na.interp计算出来了。

答案 3 :(得分:0)

imputeTS提供了一种在ARIMA模型的状态空间表示上进行卡尔曼平滑的方法-可能是解决此问题的好方法。

library(imputeTS)
na_kalman(myzoo, model = "auto.arima")

还可以直接与动物园时间序列对象一起使用。您也可以在此功能中使用自己的ARIMA模型。如果您认为可以做得更好,请选择“ auto.arima”。这可以通过以下方式完成:

library(imputeTS)
usermodel <- arima(myts, order = c(1, 0, 1))$model
na_kalman(myts, model = usermodel)

但是在这种情况下,您必须将Zoo Onject转换回ts,因为arima()仅接受ts。