Se ho un set di dati che produce un grafico come il seguente, come potrei determinare algoritmicamente i valori x dei picchi mostrati (in questo caso tre di essi):
Se ho un set di dati che produce un grafico come il seguente, come potrei determinare algoritmicamente i valori x dei picchi mostrati (in questo caso tre di essi):
Risposte:
Un approccio generale consiste nel livellare i dati e quindi trovare i picchi confrontando un filtro massimo locale con il liscio . In R
:
argmax <- function(x, y, w=1, ...) {
require(zoo)
n <- length(y)
y.smooth <- loess(y ~ x, ...)$fitted
y.max <- rollapply(zoo(y.smooth), 2*w+1, max, align="center")
delta <- y.max - y.smooth[-c(1:w, n+1-1:w)]
i.max <- which(delta <= 0) + w
list(x=x[i.max], i=i.max, y.hat=y.smooth)
}
Il suo valore di ritorno include gli argomenti del maxima locale ( x
) - che risponde alla domanda - e gli indici nelle matrici x e y in cui si verificano quei massimi locali ( i
).
Esistono due parametri da sintonizzare sulle circostanze: w
è la mezza larghezza della finestra utilizzata per calcolare il massimo locale. (Il suo valore dovrebbe essere sostanzialmente inferiore alla metà della lunghezza dell'array di dati.) I valori piccoli rileveranno piccoli dossi locali mentre i valori più grandi passeranno proprio sopra quelli. Un altro - non esplicito in questo codice - è l' span
argomento del loess
più fluido. (In genere è compreso tra zero e uno; riflette una larghezza della finestra come proporzione dell'intervallo di valori x). Valori più grandi uniformano i dati in modo più aggressivo, facendo scomparire del tutto i dossi locali.
Per rendere effettiva questa ottimizzazione, creiamo una piccola funzione di test per tracciare i risultati:
test <- function(w, span) {
peaks <- argmax(x, y, w=w, span=span)
plot(x, y, cex=0.75, col="Gray", main=paste("w = ", w, ", span = ", span, sep=""))
lines(x, peaks$y.hat, lwd=2) #$
y.min <- min(y)
sapply(peaks$i, function(i) lines(c(x[i],x[i]), c(y.min, peaks$y.hat[i]),
col="Red", lty=2))
points(x[peaks$i], peaks$y.hat[peaks$i], col="Red", pch=19, cex=1.25)
}
Ecco alcuni esperimenti applicati ad alcuni dati sintetici, leggermente rumorosi.
x <- 1:1000 / 100 - 5
y <- exp(abs(x)/20) * sin(2 * x + (x/5)^2) + cos(10*x) / 5 + rnorm(length(x), sd=0.05)
par(mfrow=c(3,1))
test(2, 0.05)
test(30, 0.05)
test(2, 0.2)
Un'ampia finestra (trama centrale) o una levigatura più aggressiva (trama in basso) eliminano i massimi locali rilevati nella trama in alto. La migliore combinazione qui è probabilmente una finestra ampia e solo un livellamento delicato, poiché il livellamento aggressivo sembra spostare questi picchi (vedere i punti centrale e destro nella trama inferiore e confrontare le loro posizioni con i picchi apparenti dei dati grezzi). In questo esempio, w=50
e span=0.05
fa un grande lavoro (non mostrato).
Notare che i massimi locali agli endpoint non vengono rilevati. Questi possono essere ispezionati separatamente. (A supporto di ciò, argmax
restituisce i valori y uniformi.)
Questo approccio presenta numerosi vantaggi rispetto alla modellazione più formale per il lavoro per scopi generali:
Non adotta alcun modello preconcetto dei dati.
Può essere adattato alle caratteristiche dei dati.
Può essere adattato per rilevare i tipi di picchi a cui è interessato.
w
e span
, e anche scoprire che valori più alti di span
stavano spostando i picchi. Sembra che anche questi passaggi possano essere automatizzati. Ad esempio per il primo numero, se potessimo valutare la qualità dei picchi scoperti, potremmo eseguire optimize
i parametri! Per il secondo problema, ad es. Scegliere una finestra su entrambi i lati del picco scoperto e cercare valori più alti.
Come ho detto nel commento, se le serie temporali sembrano adattarsi periodicamente a un modello di regressione armonica offre un modo per rendere più liscia la funzione e identificare il picco applicando il primo e il secondo test derivativo. Huber ha sottolineato un test non parametrico che presenta vantaggi in presenza di più picchi e la funzione non è necessariamente periodica. Ma non c'è pranzo libero. Mentre ci sono i vantaggi del suo metodo che menziona, possono esserci degli svantaggi se un modello parametrico è appropriato. Questo è sempre il rovescio della medaglia nell'uso di tecniche non parametriche. Sebbene eviti ipotesi parametriche, l'approccio parametrico è migliore quando le assunzioni parametriche sono appropriate. Inoltre, la sua procedura non sfrutta appieno la struttura delle serie temporali nei dati.
Penso che sia opportuno sottolineare i vantaggi di una procedura suggerita, ma è anche importante sottolineare i potenziali svantaggi. Sia il mio approccio che quello di Huber trovano le vette in modo efficiente. Tuttavia, penso che la sua procedura richieda un po 'più di lavoro quando un massimo locale è inferiore al picco più alto precedentemente determinato.
Un classico approccio di rilevamento dei picchi nell'elaborazione del segnale è il seguente:
Un altro approccio che funziona è quello di confrontare un segnale filtrato nettamente passa-alto con un segnale fortemente livellato (passa-basso o filtrato mediano) e applicare il passaggio 3.
Spero che sia di aiuto.