我有一个时间序列,我想要智能地插入缺失值。特定时间的价值受多日趋势以及其在日常周期中的位置的影响。
以下是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的向量。解决方案可能有reshape
,na.spline
和diff.inv
的某种组合,但我无法理解。
以下三种方法不起作用:
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)
答案 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.interp
。 na.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。