(Diese Antwort beantwortete eine doppelte (jetzt geschlossene) Frage unter Erkennen ausstehender Ereignisse , in der einige Daten in grafischer Form dargestellt wurden.)
Die Erkennung von Ausreißern hängt von der Art der Daten ab und davon, was Sie davon erwarten. Allzweckmethoden basieren auf robusten Statistiken. Bei diesem Ansatz geht es darum, den Großteil der Daten so zu charakterisieren, dass sie nicht von Ausreißern beeinflusst werden, und dann auf einzelne Werte zu verweisen, die nicht in diese Charakterisierung passen.
Da es sich um eine Zeitreihe handelt, ist es zusätzlich kompliziert, ständig Ausreißer (neu) erkennen zu müssen. Wenn dies im Verlauf der Serie geschehen soll, dürfen wir nur ältere Daten für die Erkennung verwenden, keine zukünftigen Daten! Zum Schutz vor den vielen wiederholten Tests möchten wir außerdem eine Methode verwenden, die eine sehr niedrige Rate an falsch positiven Ergebnissen aufweist.
Diese Überlegungen lassen darauf schließen, dass ein einfacher, robuster Ausreißertest für sich bewegende Fenster über die Daten ausgeführt wird . Es gibt viele Möglichkeiten, aber eine einfache, leicht zu verstehende und leicht zu implementierende basiert auf einem laufenden MAD: Median der absoluten Abweichung vom Median. Dies ist ein stark robustes Maß für die Variation innerhalb der Daten, ähnlich einer Standardabweichung. Ein äußerer Peak wäre mehrere MADs oder mehr größer als der Median.
Es bleibt noch einiges zu tun : Wie stark sollte eine Abweichung von der Masse der Daten von außen betrachtet werden, und wie weit sollte man in der Zeit zurückschauen? Lassen wir diese als Parameter für das Experimentieren. Hier ist eine R
Implementierung, die auf Daten (mit , um die Daten zu emulieren) mit entsprechenden Werten angewendet wird :n = 1150 yx=(1,2,…,n)n=1150y
# Parameters to tune to the circumstances:
window <- 30
threshold <- 5
# An upper threshold ("ut") calculation based on the MAD:
library(zoo) # rollapply()
ut <- function(x) {m = median(x); median(x) + threshold * median(abs(x - m))}
z <- rollapply(zoo(y), window, ut, align="right")
z <- c(rep(z[1], window-1), z) # Use z[1] throughout the initial period
outliers <- y > z
# Graph the data, show the ut() cutoffs, and mark the outliers:
plot(x, y, type="l", lwd=2, col="#E00000", ylim=c(0, 20000))
lines(x, z, col="Gray")
points(x[outliers], y[outliers], pch=19)
Auf einen Datensatz wie die in der Frage dargestellte rote Kurve angewendet, ergibt sich folgendes Ergebnis:
Die Daten werden in Rot angezeigt, das 30-Tage-Fenster des Medians + 5 * MAD-Schwellenwerte in Grau und die Ausreißer - das sind einfach die Datenwerte über der Graukurve - in Schwarz.
(Der Schwellenwert kann nur ab dem Ende des Anfangsfensters berechnet werden . Für alle Daten in diesem Anfangsfenster wird der erste Schwellenwert verwendet. Deshalb ist die graue Kurve flach zwischen x = 0 und x = 30.)
Die Auswirkungen der Änderung der Parameter sind: (a) Erhöhen des Werts von window
glättet tendenziell die Graukurve und (b) Erhöhen threshold
der Graukurve. Wenn man dies weiß, kann man ein anfängliches Segment der Daten nehmen und schnell Werte der Parameter identifizieren, die die äußeren Peaks am besten vom Rest der Daten trennen. Wenden Sie diese Parameterwerte an, um den Rest der Daten zu überprüfen. Wenn ein Diagramm anzeigt, dass sich die Methode im Laufe der Zeit verschlechtert, bedeutet dies, dass sich die Art der Daten ändert und die Parameter möglicherweise neu eingestellt werden müssen.
Beachten Sie, wie wenig diese Methode von den Daten annimmt: Sie müssen nicht normal verteilt sein. Sie müssen keine Periodizität aufweisen. Sie müssen nicht einmal negativ sein. Es wird lediglich davon ausgegangen, dass sich die Daten im Laufe der Zeit auf einigermaßen ähnliche Weise verhalten und die äußeren Spitzen sichtbar höher sind als die übrigen Daten.
Wenn jemand experimentieren möchte (oder eine andere Lösung mit der hier angebotenen vergleichen möchte), ist hier der Code, mit dem ich Daten wie die in der Frage gezeigten erstellt habe.
n.length <- 1150
cycle.a <- 11
cycle.b <- 365/12
amp.a <- 800
amp.b <- 8000
set.seed(17)
x <- 1:n.length
baseline <- (1/2) * amp.a * (1 + sin(x * 2*pi / cycle.a)) * rgamma(n.length, 40, scale=1/40)
peaks <- rbinom(n.length, 1, exp(2*(-1 + sin(((1 + x/2)^(1/5) / (1 + n.length/2)^(1/5))*x * 2*pi / cycle.b))*cycle.b))
y <- peaks * rgamma(n.length, 20, scale=amp.b/20) + baseline