(Esta respuesta respondió a una pregunta duplicada (ahora cerrada) en Detección de eventos pendientes , que presentó algunos datos en forma gráfica).
La detección de valores atípicos depende de la naturaleza de los datos y de lo que esté dispuesto a asumir sobre ellos. Los métodos de uso general se basan en estadísticas sólidas. El espíritu de este enfoque es caracterizar la mayor parte de los datos de una manera que no esté influenciada por valores atípicos y luego señalar cualquier valor individual que no se ajuste a esa caracterización.
Debido a que esta es una serie temporal, agrega la complicación de la necesidad de (re) detectar valores atípicos de manera continua. Si esto se va a hacer a medida que se desarrolla la serie, entonces solo se nos permite usar datos más antiguos para la detección, ¡no datos futuros! Además, como protección contra las muchas pruebas repetidas, nos gustaría utilizar un método que tenga una tasa muy baja de falsos positivos.
Estas consideraciones sugieren ejecutar una prueba atípica de ventana móvil simple y robusta sobre los datos . Hay muchas posibilidades, pero una simple, fácil de entender e implementar, se basa en un MAD en ejecución: desviación media absoluta de la mediana. Esta es una medida de variación muy sólida dentro de los datos, similar a una desviación estándar. Un pico periférico sería de varios MAD o más que la mediana.
R
x=(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)
Aplicado a un conjunto de datos como la curva roja ilustrada en la pregunta, produce este resultado:
Los datos se muestran en rojo, la ventana de 30 días de mediana + 5 * umbrales MAD en gris, y los valores atípicos, que son simplemente esos valores de datos por encima de la curva gris, en negro.
(El umbral solo se puede calcular comenzando al final de la ventana inicial. Para todos los datos dentro de esta ventana inicial, se usa el primer umbral: es por eso que la curva gris es plana entre x = 0 yx = 30).
Los efectos de cambiar los parámetros son (a) aumentar el valor de window
tenderá a suavizar la curva gris y (b) aumentar threshold
aumentará la curva gris. Sabiendo esto, uno puede tomar un segmento inicial de los datos e identificar rápidamente los valores de los parámetros que mejor separan los picos periféricos del resto de los datos. Aplique estos valores de parámetros para verificar el resto de los datos. Si una gráfica muestra que el método está empeorando con el tiempo, eso significa que la naturaleza de los datos está cambiando y los parámetros pueden necesitar un nuevo ajuste.
Observe lo poco que supone este método sobre los datos: no tienen que distribuirse normalmente; no necesitan exhibir ninguna periodicidad; ni siquiera tienen que ser no negativos. Todo lo que supone es que los datos se comportan de manera razonablemente similar a lo largo del tiempo y que los picos periféricos son visiblemente más altos que el resto de los datos.
Si a alguien le gustaría experimentar (o comparar alguna otra solución con la que se ofrece aquí), aquí está el código que utilicé para producir datos como los que se muestran en la pregunta.
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