Come utilizzare auto.arima per imputare i valori mancanti


12

Ho una serie di zoo con molti valori mancanti. Ho letto che auto.arimapuò imputare questi valori mancanti? Qualcuno può insegnarmi come farlo? molte grazie!

Questo è quello che ho provato, ma senza successo:

fit <- auto.arima(tsx)
plot(forecast(fit))

In aggiunta a javlacalle e alla mia risposta di seguito: nel frattempo ho implementato questi nel pacchetto imputeTS. La funzione si chiama na.kalman e esegue il livellamento di Kalman sulla forma spazio-stato di un modello ARIMA
stats0007,

Risposte:


25

Innanzitutto, forecasttieni presente che calcola le previsioni fuori campione ma sei interessato alle osservazioni all'interno del campione.

Il filtro Kalman gestisce i valori mancanti. Pertanto, è possibile prendere la forma dello spazio degli stati del modello ARIMA dall'output restituito da forecast::auto.arimao stats::arimae passarlo a KalmanRun.

Modifica (risolto nel codice in base alla risposta di stats0007)

yt=Zαt

Uso un tsoggetto come serie di esempio anziché zoo, ma dovrebbe essere lo stesso:

require(forecast)
# sample series
x0 <- x <- log(AirPassengers)
y <- x
# set some missing values
x[c(10,60:71,100,130)] <- NA
# fit model
fit <- auto.arima(x)
# Kalman filter
kr <- KalmanRun(x, fit$model)
# impute missing values Z %*% alpha at each missing observation
id.na <- which(is.na(x))
for (i in id.na)
  y[i] <- fit$model$Z %*% kr$states[i,]
# alternative to the explicit loop above
sapply(id.na, FUN = function(x, Z, alpha) Z %*% alpha[x,], 
  Z = fit$model$Z, alpha = kr$states)
y[id.na]
# [1] 4.767653 5.348100 5.364654 5.397167 5.523751 5.478211 5.482107 5.593442
# [9] 5.666549 5.701984 5.569021 5.463723 5.339286 5.855145 6.005067

È possibile tracciare il risultato (per l'intera serie e per l'intero anno con osservazioni mancanti nel mezzo del campione):

par(mfrow = c(2, 1), mar = c(2.2,2.2,2,2))
plot(x0, col = "gray")
lines(x)
points(time(x0)[id.na], x0[id.na], col = "blue", pch = 19)
points(time(y)[id.na], y[id.na], col = "red", pch = 17)
legend("topleft", legend = c("true values", "imputed values"), 
  col = c("blue", "red"), pch = c(19, 17))
plot(time(x0)[60:71], x0[60:71], type = "b", col = "blue", 
  pch = 19, ylim = range(x0[60:71]))
points(time(y)[60:71], y[60:71], col = "red", pch = 17)
lines(time(y)[60:71], y[60:71], col = "red")
legend("topleft", legend = c("true values", "imputed values"), 
  col = c("blue", "red"), pch = c(19, 17), lty = c(1, 1))

trama della serie originale e dei valori imputati a osservazioni mancanti

Puoi ripetere lo stesso esempio usando il Kalman più liscio invece del filtro Kalman. Tutto ciò che devi cambiare sono queste linee:

kr <- KalmanSmooth(x, fit$model)
y[i] <- kr$smooth[i,]

La gestione delle osservazioni mancanti mediante il filtro Kalman viene talvolta interpretata come estrapolazione della serie; quando viene usato il Kalman più liscio, si dice che le osservazioni mancanti siano riempite per interpolazione nelle serie osservate.


model

makeARIMAidmakeARIMAZ <- c(1, rep.int(0, r - 1L), Delta)Deltalength(tmp)==1idZyt-1

1
@ user3730957 Ho aggiornato la mia risposta risolvendo questo problema con l'indicizzazione.
javlacalle,

2

Ecco la mia soluzione:

# Take AirPassengers as example
data <- AirPassengers

# Set missing values
data[c(44,45,88,90,111,122,129,130,135,136)] <- NA


missindx <- is.na(data)

arimaModel <- auto.arima(data)
model <- arimaModel$model

#Kalman smoothing
kal <- KalmanSmooth(data, model, nit )
erg <- kal$smooth  

for ( i in 1:length(model$Z)) {
       erg[,i] = erg[,i] * model$Z[i]
}
karima <-rowSums(erg)

for (i in 1:length(data)) {
  if (is.na(data[i])) {
    data[i] <- karima[i]
  }
}
#Original TimeSeries with imputed values
print(data)

@ Javlacalle:

Grazie per il tuo post, molto interessante!

Ho due domande per la tua soluzione, spero che tu mi possa aiutare:

  1. Perché usi KalmanRun invece di KalmanSmooth? Ho letto che KalmanRun è considerato estrapolazione, mentre liscia sarebbe stima.

  2. Inoltre non ottengo la tua parte ID. Perché non usi tutti i componenti in .Z? Intendo ad esempio .Z dà 1, 0,0,0,0,1, -1 -> 7 valori. Ciò significherebbe .smooth (nel tuo caso per gli stati di KalmanRun) mi dà 7 colonne. Come ho capito alle colonne che sono 1 o -1, vado nel modello.

    Diciamo che la riga numero 5 non è presente in AirPass. Quindi prenderei la somma della riga 5 in questo modo: aggiungerei valore dalla colonna 1 (perché Z ha dato 1), non aggiungerei la colonna 2-4 (perché Z dice 0), aggiungerei la colonna 5 e vorrei aggiungi il valore negativo della colonna 7 (perché Z dice -1)

    La mia soluzione è sbagliata? O stanno entrambi bene? Puoi forse spiegarmi ulteriormente?


Consiglierei di pubblicare la seconda parte della tua risposta come commenti al post di @ Javlacalle piuttosto che all'interno della tua risposta.
Patrick Coulombe,

provato ... ma dice che devo avere 50 reputazione per commentare
stats0007
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.