Обнаружение аномалий в анализе временных рядов

Существует множество способов обнаружения аномалий в стандартном анализе данных. Такие методы, как Isolation Forest, DBScan, кластеризация K-средних, расстояние Кука или даже простые диаграммы и стандартное отклонение, могут помочь отсеять переменные, которые могут исказить модель, и дать уверенность в том, где провести линию относительно того, что является аномалией и что не так.

Анализ временных рядов немного отличается, поскольку временной компонент может исказить, что является аномалией, а что нет.

Например, рассмотрим график обратной функции 1/x. По мере того, как значения x становятся меньше, график резко качается вверх. Если вы поместите все эти значения в алгоритм обнаружения аномалий, он, вероятно, пометит эти значения вблизи x = 0 как аномальные. Они намного больше, чем что-либо еще.

Но поскольку это временной ряд, и мы склонны считать его частью непрерывной функции, они не являются аномальными.

Это выяснилось во время анализа тенденций смертности в США. Посмотрите на изменение количества смертей и посмотрите, сможете ли вы увидеть, какие значения могут быть аномальными.

Похоже, что тренд соответствует извилистой кривой, которая идет все выше и выше, и есть пара значений, которые выделяются из этой кривой и выделены красным. Но являются ли они более аномальными, чем другие?

Один из способов определить, насколько аномальным является значение, — посмотреть, насколько сильно оно искажает модель. И один из способов сделать это — измерить, как меняется точность модели при добавлении или удалении значений.

Итак, мой подход заключается в том, чтобы получить базовую модель со всеми данными, а затем путем проб и ошибок удалить случайные точки данных и проверить, насколько это влияет на модель.

В случае данных о смертности в США нам нужна линейная интерполяция. Мы можем использовать sklearn или statsmodels, но для простоты я буду использовать функцию numpy polyfit.

Это просто вопрос определения полинома какой степени использовать. Для этого я пройдусь по каждой степени полинома и посмотрю, какая из них подходит лучше всего.

x = df.Year
y = df.Deaths
vals = []
for j in range(1,7):
    z = np.polyfit(x, y, j)
    p = np.poly1d(z)
    errs = [abs(y.iloc[i] - v) for i, v in enumerate(p(x))]
    vals.append([j, mean(errs)])

И мы можем ясно видеть, что ошибки перестают улучшаться около полинома 3-й и 4-й степени. Мы не только хотим устранить аномалии, чтобы улучшить качество подгонки модели, но также было бы здорово иметь более простую модель. Полином более высокой степени может привести к переоснащению и плохому прогнозу в будущем.

Таким образом, начиная с полинома 3-й степени, мы можем просмотреть каждую точку данных, удалить эту точку, а затем посмотреть, как модель работает без нее.

vals = []
for j in range(len(df) - 1):
    tmp = df[df.index != j][0:-1]
    x = tmp.Year
    y = tmp.Deaths
    
    z = np.polyfit(x, y, 3)
    p = np.poly1d(z)
    errs = [abs(y.iloc[i] - v) for i, v in enumerate(p(x))]
    vals.append([df.Year.iloc[j], max(errs), mean(errs)])
   

Мы можем быстро увидеть, что данные не за 2004 или 2006 год искажали модель, а за 2019 год. Без этого года средняя ошибка значительно ниже.

Это может показаться странным, поскольку 2019 год не выглядит странным, если посмотреть на исходный график данных, но при попытке подогнать линейный график к данным вы можете понять, почему 2019 год искажает модель.

Включение данных за 2019 год не помогает модели приблизиться к этой точке данных. Полином 3-й или 4-й степени не может сделать крутой крутой поворот в самом конце. В противном случае обе линейные посадки эффективно сидят друг над другом.

Хотя 2004 и 2006 годы находятся в стороне от линии тренда, они не искажают линию тренда. То есть, если их убрать, линия тренда ориентировалась бы примерно в том же положении.

По мере увеличения размера данных этот метод программных проб и ошибок требует больших ресурсов процессора и времени — подобно поиску по сетке по параметрам, — но есть способы ограничить возможности такого поиска.

Но усилия по обработке могут того стоить. Иногда выявление аномалий важнее самой модели в зависимости от масштаба проекта.