Вот как обнаружить точечные аномалии в каждой серии и выявить аномальные сигналы по всей территории банка.
Делиться

Один из самых захватывающих аспектов временных рядов — это присущая этим, казалось бы, простым данным сложность .
В конечном итоге, во временных рядах у вас есть ось X, которая обычно представляет время (t), и ось A, которая представляет интересующую величину (цена акций, температура, трафик, клики и т. д.). Это значительно проще, чем, например, видео, где у вас могут быть тысячи изображений, и каждое изображение представляет собой тензор ширины, высоты и трех каналов (RGB).
Однако сложность заключается в эволюции интересующей нас величины (ось Y) во времени (ось X). Выявляет ли эта эволюция тенденцию ? Есть ли в ней точки данных , которые явно отклоняются от ожидаемого сигнала? Стабильна ли она или непредсказуема? Превышает ли среднее значение величины ожидаемое? Все это можно в той или иной степени определить как аномалии .
Данная статья представляет собой сборник различных методов обнаружения аномалий. Цель состоит в том, чтобы, имея набор данных, состоящий из нескольких временных рядов, определить, какой из временных рядов является аномальным и почему .
Вот 4 аномалии временных рядов, которые мы собираемся обнаружить:
- Мы собираемся выявить любую тенденцию в нашем временном ряду (аномалию тренда ).
- Мы собираемся оценить, насколько изменчив временной ряд ( аномалия волатильности ).
- Мы собираемся обнаружить точечные аномалии во временном ряду ( одноточечные аномалии ).
- Мы собираемся выявить аномалии в нашем наборе сигналов, чтобы понять, какой сигнал ведет себя иначе, чем остальные сигналы в нашем наборе ( аномалии на уровне набора данных ).

Мы теоретически опишем каждый метод обнаружения аномалий из этой коллекции и покажем его реализацию на Python. Весь код, использованный в этой статье, находится в папке PieroPaialungaAI/timeseriesanomaly на GitHub.
0. Набор данных
Для создания сборщика аномалий нам необходим набор данных, в котором мы точно знаем, какую аномалию ищем, чтобы понимать, работает ли наш детектор аномалий или нет. Для этого я создал скрипт data.py. Скрипт содержит объект DataGenerator, который:
- Считывает конфигурацию нашего набора данных из файла config.json*.
- Создает набор данных об аномалиях.
- Предоставляет возможность легко сохранять данные и строить на их основе графики.
Вот фрагмент кода:

Таким образом, мы видим, что у нас есть:
- Общая временная ось , от 0 до 100
- Несколько временных рядов , образующих набор данных временных рядов.
- Каждый временной ряд содержит одну или несколько аномалий .
Аномалии, как и ожидалось, следующие:
- Трендовое поведение , при котором временной ряд имеет линейную или полиномиальную степень.
- Волатильность — это ситуация , когда временной ряд более изменчив и непостоянен, чем обычно.
- Сдвиг уровня , при котором среднее значение временного ряда выше, чем обычно.
- Точечная аномалия — это аномалия, при которой временной ряд содержит одну аномальную точку.
Теперь наша цель — создать набор инструментов , способных выявлять каждую из этих аномалий во всем наборе данных.
Файл config.json позволяет изменять все параметры нашего набора данных, такие как количество временных рядов, ось временного ряда и тип аномалий. Вот как он выглядит:
1. Выявление аномалий тренда
1.1 Теория
Когда мы говорим об «аномалии тренда», мы ищем структурное поведение : временной ряд движется вверх или вниз, или же имеет устойчивую форму изгиба. Это важно для реальных данных, поскольку дрейф часто означает деградацию датчиков, изменение поведения пользователей, проблемы с моделью/конвейером обработки данных или другое скрытое явление, которое необходимо исследовать в вашем наборе данных.
Мы рассматриваем два типа тенденций:
- Линейная регрессия : мы аппроксимируем временной ряд линейным трендом.
- Полиномиальная регрессия : мы аппроксимируем временной ряд полиномом низкой степени.
На практике мы измеряем ошибку модели линейной регрессии. Если она слишком велика, мы используем модель полиномиальной регрессии. Мы считаем тренд «значимым», если значение p ниже установленного порогового значения (обычно p < 0,05).
1.2 Код
Объект AnomalyDetector в файле anomaly_detector.py выполнит описанный выше код, используя следующие функции:
- Детектор , который загрузит данные, сгенерированные нами в DataGenerator.
- Функции detect_trend_anomaly и detect_all_trends определяют (возможный) тренд для отдельного временного ряда и для всего набора данных соответственно.
- Функция get_series_with_trend возвращает индексы, имеющие значимый тренд.
Мы можем использовать функцию plot_trend_anomalies для отображения временного ряда и оценки прогресса:

Отлично! Значит, мы можем без ошибок извлечь «модный» временной ряд из нашего набора данных. Давайте продолжим!
2. Выявление аномалий волатильности
2.1 Теория
Теперь, когда у нас есть глобальный тренд, мы можем сосредоточиться на волатильности. Под волатильностью я подразумеваю, говоря простым языком, насколько изменчив наш временной ряд? Точнее, как дисперсия временного ряда соотносится со средним значением нашего набора данных?
Вот как мы собираемся проверить эту аномалию:
- Мы собираемся удалить тренд из набора данных временных рядов.
- Мы собираемся найти статистические данные по дисперсии.
- Мы собираемся выявить выбросы в этих статистических данных.
Довольно просто, правда? Давайте приступим к коду!
2.2 Код
Аналогично тому, что мы сделали для анализа трендов, мы применили следующие подходы:
- Функция detect_volatility_anomaly проверяет, имеет ли данный временной ряд аномалию волатильности или нет.
- Функции detect_all_volatilities и get_series_with_high_volatility проверяют все наборы данных временных рядов на наличие аномалий волатильности и возвращают соответствующие индексы аномалий.
Вот как мы отображаем результаты:

3. Одноточечная аномалия
3.1 Теория
Хорошо, теперь давайте проигнорируем все остальные временные ряды набора данных и сосредоточимся на каждом временном ряду по отдельности. Для интересующего нас временного ряда мы хотим определить, есть ли среди них точка , явно являющаяся аномальной. Существует множество способов сделать это; мы можем использовать трансформеры, одномерные сверточные нейронные сети, LSTM, кодировщики-декодеры и т. д. Для простоты давайте воспользуемся очень простым алгоритмом:
- Мы собираемся использовать метод скользящего окна , при котором окно фиксированного размера будет перемещаться слева направо.
- Для каждой точки мы вычисляем среднее значение и стандартное отклонение окружающего ее окна (исключая саму точку).
- Мы вычисляем, на сколько стандартных отклонений точка удалена от своей локальной окрестности, используя Z-оценку.
Мы определяем точку как аномальную , если она превышает фиксированное значение Z-показателя. Мы будем использовать Z-показатель = 3, что означает утроенное стандартное отклонение.
3.2 Код
Аналогично тому, что мы сделали для анализа трендов и волатильности, мы применили следующие подходы:
- Функция detect_point_anomaly проверяет наличие одноточечных аномалий в заданном временном ряду, используя метод скользящего окна Z-оценки.
- Функции detect_all_point_anomalies и get_series_with_point_anomalies проверяют весь набор данных временных рядов на наличие точечных аномалий и возвращают индексы рядов, содержащих хотя бы одну аномальную точку, соответственно.
Вот как это работает:

4. Аномалия на уровне набора данных
4.1 Теория
Эта часть намеренно упрощена. Здесь мы ищем не странные моменты времени, а странные сигналы в банке. Мы хотим ответить на следующий вопрос:
Есть ли какие-либо временные ряды, общая величина которых значительно больше (или меньше), чем мы ожидаем, исходя из остального набора данных?
Для этого мы сводим каждый временной ряд к одному «базовому» значению (типичному уровню), а затем сравниваем эти базовые значения по всему банку. Сравнение будет проводиться с использованием медианы и Z-показателя .
4.2 Код
Вот как мы выявляем аномалии на уровне набора данных:
- Функция detect_dataset_level_anomalies() находит аномалии на уровне всего набора данных.
- Функция get_dataset_level_anomalies() находит индексы, которые демонстрируют аномалию на уровне набора данных.
- Функция plot_dataset_level_anomalies() отображает пример временного ряда, в котором наблюдаются аномалии.
Вот код для этого:

5. Все вместе!
Итак, пора всё это объединить. Мы будем использовать detector.detect_all_anomalies() и оценивать аномалии для всего набора данных на основе тренда, волатильности, отдельных точек и аномалий на уровне набора данных . Скрипт для этого очень прост:
Функция `df` покажет вам аномалию для каждого временного ряда. Вот как это выглядит:
Если мы воспользуемся следующей функцией, мы сможем увидеть это в действии:

Впечатляюще, правда? Мы это сделали! 🙂
6. Выводы
Спасибо, что уделили нам время, это очень много значит для нас. ❤️ Вот что мы сделали вместе:
- Разработал небольшой набор инструментов для обнаружения аномалий в массиве временных рядов .
- Аномалии тренда выявлялись с помощью линейной регрессии, а в случаях, когда линейной аппроксимации было недостаточно, — с помощью полиномиальной регрессии.
- Аномалии волатильности были выявлены путем сначала удаления тренда, а затем сравнения дисперсии по всему набору данных.
- Выявление аномалий в отдельных точках с помощью скользящего окна Z-оценки (простой, быстрый и удивительно эффективный метод).
- Аномалии на уровне набора данных были обнаружены путем сжатия каждой серии до базового уровня (медианы) и пометки сигналов, находящихся в другом масштабе величины.
- Объединить все данные в единый конвейер, который возвращает чистую сводную таблицу, которую мы можем просмотреть или построить график.
Во многих реальных проектах набор инструментов, подобный тому, что мы здесь создали, очень помогает, потому что:
- Это позволяет получать объяснимые сигналы (тренд, волатильность, сдвиг базовой линии, локальные выбросы).
- Это даст вам хорошую отправную точку, прежде чем переходить к более тяжелым моделям.
- Она хорошо масштабируется при большом количестве сигналов , именно в таких случаях обнаружение аномалий обычно становится проблематичным.
Следует помнить, что базовый алгоритм намеренно упрощен и использует очень простые статистические данные. Однако модульность кода позволяет легко добавить сложность, просто добавив функциональность в файлы anomaly_detector_utils.py и anomaly_detector.py.
7. Перед тем, как отправиться в путь!
Ещё раз большое спасибо за ваше время. Это очень много значит для меня ❤️
Меня зовут Пьеро Пайалунга, а вот этот парень:

Я родом из Италии, имею докторскую степень Университета Цинциннати и работаю специалистом по анализу данных в компании The Trade Desk в Нью-Йорке. Я пишу об искусственном интеллекте, машинном обучении и меняющейся роли специалистов по анализу данных как здесь, на TDS, так и в LinkedIn. Если вам понравилась статья и вы хотите узнать больше о машинном обучении и следить за моими исследованиями, вы можете:
А. Подписывайтесь на меня в LinkedIn , где я публикую все свои истории.
Б. Подпишитесь на меня в GitHub , где вы сможете увидеть весь мой код.
C. По всем вопросам вы можете отправить мне электронное письмо по адресу piero.paialunga@hotmail.
Источник: towardsdatascience.com























