Come posso evidenziare patch rumorose in una serie temporale?


9

Ho molti dati sulle serie temporali: livelli e velocità dell'acqua rispetto al tempo. È l'output di una simulazione del modello idraulico. Come parte del processo di revisione per confermare che il modello funziona come previsto, devo tracciare ogni serie temporale per assicurarmi che non ci siano "oscillazioni" nei dati (vedi esempio di oscillazione minore di seguito). L'uso dell'interfaccia utente del software di modellazione è un modo piuttosto lento e laborioso di controllare questi dati. Ho quindi scritto una breve macro VBA per importare vari bit di dati dal modello, inclusi i risultati in Excel, e tracciarli tutti in una volta. Spero di scrivere un'altra breve macro VBA per analizzare i dati delle serie temporali ed evidenziare eventuali sezioni sospette.

Il mio unico pensiero finora è che potrei fare qualche analisi sulla pendenza dei dati. Ovunque una pendenza che cambi rapidamente da positiva a negativa più volte all'interno di una determinata finestra di ricerca potrebbe essere classificata come instabile. Mi sto perdendo qualche trucco più semplice? In sostanza, una simulazione "stabile" dovrebbe fornire una curva molto regolare. Eventuali cambiamenti improvvisi sono probabilmente il risultato di un'instabilità nei calcoli.

Esempio di instabilità minore


1
Leggi il libro EDA di Tukey per una serie di metodi semplici. All'inizio del libro, ad esempio, descrive semplici leviganti e il loro uso per ottenere residui. Un seguito graduale dei residui assoluti tracciava la variabilità locale delle tue curve, andando in alto dove hai cambiamenti rapidi, improvvisi o periferici, e altrimenti rimanendo basso. Sono possibili molti metodi molto più sofisticati, ma forse questo sarebbe sufficiente. Gli smussatori di Tukey sono relativamente facili da codificare in VBA: l' ho fatto .
whuber

@whuber Questa è essenzialmente la potenza del filtro passa-alto scorrevole?
amoeba,

@amoeba Forse. La mia comprensione di tali filtri è che non sono interamente locali e sicuramente non sono robusti, mentre i leviganti di Tukey hanno entrambe queste importanti proprietà. (Oggi le persone usano Loess o GAM per il livellamento, il che va bene, ma quelli sono molto meno semplici da implementare.)
whuber

Risposte:


10

1αα

figura

1201α=0.201

αα0.20α0.20

I dettagli del liscio non contano molto. In questo esempio è stato usato un loess smooth (implementato in Ras loesscon span=0.05per localizzarlo), ma anche una media con finestra avrebbe fatto bene. Per appianare i residui assoluti ho eseguito una media a finestra di larghezza 17 (circa 24 minuti) seguita da una mediana a finestra. Questi smooth con finestre sono relativamente facili da implementare in Excel. Un'implementazione VBA efficiente (per le versioni precedenti di Excel, ma il codice sorgente dovrebbe funzionare anche nelle nuove versioni) è disponibile all'indirizzo http://www.quantdec.com/Excel/smoothing.htm .


R Codice

#
# Emulate the data in the plot.
#
xy <- matrix(c(0, 96.35,  0.3, 96.6, 0.7, 96.7, 1, 96.73, 1.5, 96.74, 2.5, 96.75, 
               4, 96.9, 5, 97.05, 7, 97.5, 10, 98.5, 12, 99.3, 12.5, 99.35, 
               13, 99.355, 13.5, 99.36, 14.5, 99.365, 15, 99.37, 15.5, 99.375, 
               15.6, 99.4, 15.7, 99.41, 20, 99.5, 25, 99.4, 27, 99.37),
             ncol=2, byrow=TRUE)
n <- 401
set.seed(17)
noise.x <- cumsum(rexp(n, n/max(xy[,1])))
noise.y <- rep(c(-1,1), ceiling(n/2))[1:n]
noise.amp <- runif(n, 0.8, 1.2) * 0.04
noise.amp <- noise.amp * ifelse(noise.x < 16 | noise.x > 24.5, 0.05, 1)
noise.y <- noise.y * noise.amp

g <- approxfun(noise.x, noise.y)
f <- splinefun(xy[,1], xy[,2])
x <- seq(0, max(xy[,1]), length.out=1201)
y <- f(x) + g(x)
#
# Plot the data and a smooth.
#
par(mfrow=c(1,2))
plot(range(xy[,1]), range(xy[,2]), type="n", main="Data", sub="With Smooth",
     xlab="Time (hours)", ylab="Water Level")
abline(h=seq(96, 100, by=0.5), col="#e0e0e0")
abline(v=seq(0, 30, by=5), col="#e0e0e0")
#curve(f(x) + g(x), xlim=range(xy[,1]), col="#2070c0", lwd=2, add=TRUE, n=1201)
lines(x,y, type="l", col="#2070c0", lwd=2)

span <- 0.05
fit <- loess(y ~ x, span=span)
y.hat <- predict(fit)
lines(fit$x, y.hat)
#
# Plot the absolute residuals to the smooth.
#
r <-  abs(resid(fit))
plot(fit$x, r, type="l", col="#808080",
     main="Absolute Residuals", sub="With Smooth and a Threshold",
     xlab="Time hours", ylab="Residual Water Level")
#
# Smooth plot an indicator of the smoothed residuals.
#
library(zoo)
smooth <- function(x, window=17) {
  x.1 <- rollapply(ts(x), window, mean)
  x.2 <- rollapply(x.1, window, median)
  return(as.vector(x.2))
}
alpha <- 0.2
threshold <- quantile(r, 1-alpha)
abline(h=threshold, lwd=2, lty=3)
r.hat <- smooth(r >threshold)
x.hat <- smooth(fit$x)
z <- max(r)/2 * (r.hat > alpha)
lines(x.hat, z, lwd=2, col="#c02020")
par(mfrow=c(1,1))

1
+1. Hai in qualche modo raschiato i dati dalla trama del PO?
amoeba,

2
@Amoeba Sarebbe troppo disturbo, soprattutto per i pezzettini dopo 15 ore. Ho osservato una dozzina di punti sulla curva, tracciato una spline, inserito alcuni punti intermedi per eliminare gli strani picchi che una spline può produrre e ho aggiunto un errore correlato eteroscedastico fortemente negativo. L'intero processo ha richiesto solo pochi minuti e ha prodotto un set di dati qualitativamente come quello mostrato nella domanda.
whuber

Mi chiedevo come avessi ottenuto i dati dalla mia trama! Saluti! Ci proverò.
davehughes87,

FWIW, ho pubblicato il codice che ho usato per realizzare l'illustrazione. Anche se non è VBA, forse chiarirà i dettagli. (cc @amoeba)
whuber
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.