Un aspecto fascinante de las series temporales es la complejidad intrínseca de un tipo de datos aparentemente tan simple.
Al final del día, en las series de tiempo, tienes un eje x que normalmente representa el tiempo
Sin embargo, la evolución de la cantidad de interés (eje y) a lo largo del tiempo (eje x) es donde se esconde la complejidad. ¿Esta evolución presenta una tendencia? ¿Tiene algún punto de datos que se desvíe claramente de la señal esperada? ¿Es estable o impredecible? ¿Es el valor promedio de la cantidad mayor de lo que esperaríamos? Todo esto puede definirse de alguna manera como anomalías.
Este artículo es una colección de múltiples técnicas de detección de anomalías. El objetivo es que, dado un conjunto de datos de múltiples series temporales, podamos detectar qué series temporales son anómalas y por qué.
Estas son las 4 anomalías de series temporales que vamos a detectar:
Vamos a detectar cualquier tendencia en nuestra serie temporal (anomalía de tendencia) Vamos a evaluar qué tan volátil es la serie temporal (anomalía de volatilidad). Vamos a detectar las anomalías puntuales dentro de la serie temporal (anomalía de punto único). Vamos a detectar las anomalías dentro de nuestro banco de señales, para comprender qué señal se comporta de manera diferente a nuestro conjunto de señales (anomalía a nivel de conjunto de datos).
Describiremos teóricamente cada método de detección de anomalías de esta colección y mostraremos la implementación de Python. El código completo que utilicé para esta publicación de blog está incluido en la carpeta PieroPaialungaAI/timeseriesanomaly de GitHub.
0. El conjunto de datos
Para construir el recolector de anomalías, necesitamos tener un conjunto de datos donde sepamos exactamente qué anomalía estamos buscando, para saber si nuestro detector de anomalías está funcionando o no. Para hacer eso, he creado un script data.py. El script contiene un objeto DataGenerator que:
Lee la configuración de nuestro conjunto de datos desde un archivo config.json*. Crea un conjunto de datos de anomalías Le brinda la capacidad de almacenar fácilmente los datos y trazarlos.
Este es el fragmento de código:
Entonces podemos ver que tenemos:
Un eje de tiempo compartido, de 0 a 100. Múltiples series de tiempo que forman un conjunto de datos de series de tiempo. Cada serie de tiempo presenta una o varias anomalías.
Las anomalías son, como se esperaba:
El comportamiento de tendencia, donde las series de tiempo tienen un comportamiento de grado lineal o polinómico. La volatilidad, donde la serie de tiempo es más volátil y cambiante de lo normal. El cambio de nivel, donde la serie de tiempo tiene un promedio más alto de lo normal. Una anomalía de punto, donde la serie de tiempo tiene un punto anómalo.
Ahora nuestro objetivo será tener una caja de herramientas que pueda identificar cada una de estas anomalías para todo el conjunto de datos.
*El archivo config.json permite modificar todos los parámetros de nuestro conjunto de datos, como el número de series temporales, el eje de las series temporales y el tipo de anomalías. Así es como se ve:
1. Identificación de anomalías de tendencia
1.1 Teoría
Cuando decimos “una anomalía de tendencia”, buscamos un comportamiento estructural: la serie sube o baja con el tiempo, o se dobla de manera consistente. Esto es importante en los datos reales porque la deriva a menudo significa degradación del sensor, cambios en el comportamiento del usuario, problemas en el modelo/canalización de datos u otro fenómeno subyacente que se debe investigar en su conjunto de datos.
Consideramos dos tipos de tendencias:
Regresión lineal: ajustamos la serie temporal con una tendencia lineal Regresión polinómica: ajustamos la serie temporal con un polinomio de bajo grado.
En la práctica, medimos el error del modelo de Regresión Lineal. Si es demasiado grande, ajustamos el de Regresión Polinómica. Consideramos que una tendencia es “significativa” cuando el valor de p es inferior a un umbral establecido (comúnmente p <0,05).
1.2 Código
El objeto AnomalyDetector en anomaly_detector.py ejecutará el código descrito anteriormente usando las siguientes funciones:
El detector, que cargará los datos que hemos generado en DataGenerator. detect_trend_anomaly y detect_all_trends detectan la tendencia (eventual) para una única serie temporal y para todo el conjunto de datos; respectivamente, get_series_with_trend devuelve los índices que tienen una tendencia significativa.
Podemos usar plot_trend_anomalies para mostrar la serie temporal y ver cómo lo estamos haciendo:
¡Bien! Por lo tanto, podemos recuperar las series temporales “de moda” en nuestro conjunto de datos sin ningún error. ¡Sigamos adelante!
2. Identificación de anomalías de volatilidad
2.1 Teoría
Ahora que tenemos una tendencia global, podemos centrarnos en la volatilidad. Lo que quiero decir con volatilidad es, en términos sencillos, ¿cuán dispersas están nuestras series temporales? En términos más precisos, ¿cómo se compara la varianza de la serie temporal con la media de nuestro conjunto de datos?
Así es como vamos a probar esta anomalía:
Vamos a eliminar la tendencia del conjunto de datos de la serie temporal. Vamos a encontrar las estadísticas de la varianza. Vamos a encontrar los valores atípicos de estas estadísticas.
Bastante simple, ¿verdad? ¡Vamos a sumergirnos en el código!
2.2 Código
De manera similar a lo que hemos hecho para las tendencias, tenemos:
detect_volatility_anomaly, que comprueba si una serie temporal determinada tiene una anomalía de volatilidad o no. detect_all_volatilities y get_series_with_high_volatility, que verifican todos los conjuntos de datos de series temporales en busca de anomalías de volatilidad y devuelven los índices anómalos, respectivamente.
Así es como mostramos los resultados:
3. Anomalía de un solo punto
3.1 Teoría
Bien, ahora ignoremos todas las demás series de tiempo del conjunto de datos y centrémonos en cada serie de tiempo a la vez. Para nuestra serie temporal de interés, queremos ver si tenemos un punto que sea claramente anómalo. Hay muchas maneras de hacerlo; podemos aprovechar Transformers, 1D CNN, LSTM, Encoder-Decoder, etc. En aras de la simplicidad, usemos un algoritmo muy simple:
Vamos a adoptar un enfoque de ventana móvil, donde una ventana de tamaño fijo se moverá de izquierda a derecha. Para cada punto, calculamos la media y la desviación estándar de la ventana circundante (excluyendo el punto en sí). Calculamos cuántas desviaciones estándar está lejos del punto de su vecindad local usando la puntuación Z.
Definimos un punto como anómalo cuando excede un valor de puntuación Z fijo. Usaremos puntuación Z = 3, lo que significa 3 veces las desviaciones estándar.
3.2 Código
De manera similar a lo que hemos hecho para las tendencias y la volatilidad, tenemos:
detect_point_anomaly, que comprueba si una serie de tiempo determinada tiene anomalías de un solo punto utilizando el método de puntuación Z de ventana móvil. detect_all_point_anomalies y get_series_with_point_anomalies, que verifican todo el conjunto de datos de series temporales en busca de anomalías de puntos y devuelven los índices de las series que contienen al menos un punto anómalo, respectivamente.
Y así es como está funcionando:
4. Anomalía a nivel de conjunto de datos
4.1 Teoría
Esta parte es intencionalmente simple. Aquí no buscamos momentos extraños en el tiempo, buscamos señales extrañas en el banco. Lo que queremos responder es:
¿Existe alguna serie temporal cuya magnitud general sea significativamente mayor (o menor) de lo que esperamos dado el resto del conjunto de datos?
Para hacerlo, comprimimos cada serie temporal en un único número de “línea de base” (un nivel típico) y luego comparamos esas líneas de base en todo el banco. La comparación se realizará en términos de mediana y puntuación Z.
4.2 Código
Así es como hacemos la anomalía a nivel de conjunto de datos:
detect_dataset_level_anomalies(), encuentra la anomalía a nivel del conjunto de datos en todo el conjunto de datos. get_dataset_level_anomalies(), encuentra los índices que presentan una anomalía a nivel de conjunto de datos. plot_dataset_level_anomalies(), muestra una muestra de series temporales que presentan anomalías.
Este es el código para hacerlo:
5. ¡Todos juntos!
Ok, es hora de juntarlo todo. Usaremos detector.detect_all_anomalies() y evaluaremos las anomalías para todo el conjunto de datos en función de la tendencia, la volatilidad, las anomalías de un solo punto y a nivel del conjunto de datos. El script para hacer esto es muy simple:
El df le dará la anomalía para cada serie temporal. Así es como se ve:
Si usamos la siguiente función podemos verlo en acción:
Bastante impresionante ¿verdad? Lo hicimos. 🙂
6. Conclusiones
Gracias por pasar tiempo con nosotros, significa mucho. ❤️ Esto es lo que hemos hecho juntos:
Creó un pequeño conjunto de herramientas de detección de anomalías para un banco de series temporales. Se detectaron anomalías de tendencia mediante regresión lineal y regresión polinómica cuando el ajuste lineal no es suficiente. Se detectaron anomalías de volatilidad eliminando la tendencia primero y luego comparando la varianza en todo el conjunto de datos. Se detectaron anomalías de un solo punto con una puntuación Z de ventana móvil (simple, rápida y sorprendentemente efectiva). Se detectaron anomalías a nivel de conjunto de datos comprimiendo cada serie en una línea de base (mediana) y marcando señales que viven en una escala de magnitud diferente. Reúna todo en una única canalización que devuelva una tabla resumen limpia que podamos inspeccionar o trazar.
En muchos proyectos reales, una caja de herramientas como la que creamos aquí te lleva muy lejos porque:
Le brinda señales explicables (tendencia, volatilidad, cambio de referencia, valores atípicos locales). Le brinda una base sólida antes de pasar a modelos más pesados. Se adapta bien cuando hay muchas señales, que es donde la detección de anomalías suele resultar dolorosa.
Tenga en cuenta que la línea de base es simple a propósito y utiliza estadísticas muy simples. Sin embargo, la modularidad del código le permite agregar complejidad fácilmente simplemente agregando la funcionalidad en anomaly_detector_utils.py y anomaly_detector.py.
7. ¡Antes de salir!
Gracias de nuevo por tu tiempo. Significa mucho ❤️
Mi nombre es Piero Paialunga y soy este chico:
Soy originario de Italia, tengo un doctorado. de la Universidad de Cincinnati y trabaja como científico de datos en The Trade Desk en la ciudad de Nueva York. Escribo sobre IA, aprendizaje automático y la evolución del papel de los científicos de datos tanto aquí en TDS como en LinkedIn. Si te gustó el artículo y quieres saber más sobre el aprendizaje automático y seguir mis estudios, puedes:
R. Sígueme en Linkedin, donde publico todas mis historias.
B. Sígueme en GitHub, donde podrás ver todo mi código.
C. Si tienes dudas puedes enviarme un correo electrónico a piero.paialunga@hotmail