Давайте рассмотрим более практическую задачу, чем настройка полей ввода на информационных панелях.

Прогнозирование временных рядов - довольно типичная задача при анализе данных. Splunk ML Toolkit предоставляет несколько хорошо известных методов для решения этой задачи: фильтр Калмана и ARIMA. К сожалению, эти методы иногда не работают, когда сталкиваются с реальными проблемами. Итак, давайте рассмотрим их поближе, а затем рассмотрим несколько других методов прогнозирования временных рядов в Splunk.

Задача

Хорошо, давайте определимся с целью. Пусть мы используем Splunk для мониторинга некоторых показателей, таких как количество входов в систему, количество транзакций в БД и т. Д. Мы хотим проанализировать рост нашего бизнеса (например, в целях планирования мощности и управления ресурсами). В рамках этого анализа мы хотим спрогнозировать количество входов в систему в течение года на основе данных за последние несколько лет.

Как видите, довольно обычная задача. Но давайте усложним задачу с учетом требований гибкости. Поскольку мониторинг не является единственной метрикой, наш метод или алгоритм должны быть достаточно универсальными, чтобы предсказывать практически любую метрику без большой настройки пользователем. В конце концов, нам нужно построить информационную панель с такой функциональностью: пользователь выбирает метрику, указывает несколько параметров настройки и получает соответствующий прогноз выбранной метрики на год.

Тренд, сезонность и стационарность

Давайте освежим некоторые основные понятия о временных рядах. В общем, временной ряд можно разделить на несколько компонентов: компонент тренда, сезонный компонент и остаточный компонент. Тренд - это общее направление изменения значения временного ряда. Например, возрастающая тенденция означает, что значения временных рядов в среднем больше, чем предыдущие. Сезонная составляющая обозначает периодические колебания данных. Например, количество входов в систему в ночные часы постоянно меньше, чем в дневные, а также количество входов в систему в будние дни больше, чем в выходные. Остаточный компонент - это разница между значениями временного ряда и определенными компонентами (тренд, сезонность) и часто обозначает некоторый шум.

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

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

Среднее значение и дисперсия «синего» ряда равны 0 и 1 соответственно, поэтому этот ряд является стационарным. «Желтая» серия показывает возрастающую тенденцию, то есть среднее значение не является постоянным. «Красный» ряд показывает очевидную суточную сезонность, то есть функция автокорреляции имеет локальный максимум с лагами 24, 48,… часов - и он тоже непостоянен. «Фиолетовый» ряд показывает растущую тенденцию и нарушение, то есть среднее значение и дисперсия также не являются постоянными.

Временные ряды в реальном времени редко бывают стационарными. Но существует множество приемов и преобразований для превращения их в стационарные.

Давайте включим ML Toolkit и попробуем предсказать нашу серию.

Фильтр Калмана

Фильтрация Калмана - это алгоритм, который производит оценки неизвестных переменных, которые имеют тенденцию быть более точными, чем оценки, основанные только на одном измерении (извините, я скопировал определение из статьи вики). Другими словами, фильтр Калмана принимает на вход временные ряды и выполняет своего рода сглаживание и шумоподавление. После этого можно было бы предсказывать сглаженные серии. Но следует учитывать, что фильтр Калмана предназначен в первую очередь для шумоподавления, а не для прогнозирования. Поэтому результаты прогнозов могут быть немного неадекватными.

Перейдите в раздел Помощники ›Временные ряды прогнозов и выберите в качестве алгоритма фильтр Калмана.

ML Toolkit предоставляет несколько методов прогнозирования:

  • LL (локальный уровень) для прогнозирования только локального уровня временных рядов (без какой-либо тенденции или сезонности);
  • LLT (тренд локального уровня) для прогнозирования только тренда;
  • LLP (сезонный местный уровень) для прогнозирования только сезонной составляющей;
  • LLP5 (объединяет LLT и LLP) для учета как тенденции, так и сезонности.

Пример игрушки

Прежде всего, давайте попробуем применить фильтр Калмана к одному из нестационарных временных рядов из примера выше, просто чтобы проверить возможности сглаживания. Выберем «желтый» ряд - это просто сумма постоянного тренда и нормально распределенного шума. Я получил его с помощью этого запроса SPL (normal - это настраиваемая внешняя команда, которая возвращает нормально распределенное значение со средним значением и отклонением от полей, указанных в параметрах loc и scale соответственно):

| gentimes start=”01/01/2018" increment=1h
| eval _time=starttime, loc=0, scale=20
| normal loc=loc scale=scale 
| streamstats count as cnt
| eval gen_normal = gen_normal + cnt
| table _time, gen_normal
| rename gen_normal as “Non-stationary time series (trend)”

Хорошо, давайте применим фильтр Калмана с алгоритмом «LLT», будущий временной интервал = 200, доверительный интервал = 95.

Выглядит хорошо. Фильтр действительно удаляет нормально распределенный шум и предсказывает реальный тренд.

Серьезный разговор

Теперь давайте попробуем предсказать количество наших входов в систему. Наши временные ряды, очевидно, включают в себя как тенденции, так и сезонные компоненты, поэтому давайте выберем алгоритм прогнозирования = LLP5, будущий временной интервал = 365 (прогноз на год), период = 365 (поскольку мы ожидаем, что этот сезонный период будет самым большим).

Что ж ... Совершенно очевидно, что результат немного не такой, как ожидалось. Похоже, фильтр рассматривает наши колебания данных как шум. Таким образом, фильтр устраняет этот шум и сохраняет только компонент тренда. Но немного смущает то, что часть алгоритма «LLP», отвечающая за сезонную составляющую, вообще не работает. В любом случае такой прогноз неприемлем.

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

| inputlookup daylogins.csv
| timechart span=1d fixedrange=f max(daylogins) as daylogins
| predict “daylogins” as prediction algorithm=”LLT” future_timespan=365 period=365 lower”95"=lower”95" upper”95"=upper”95"
| eval daylogins = case(daylogins < ‘lower95(prediction)’, ‘lower95(prediction)’, daylogins > ‘upper95(prediction)’, ‘upper95(prediction)’, 1=1, daylogins)
| eval season = daylogins / prediction
| table _time, season
| where _time<strptime(“2018–01–01”, “%F”)

Здесь я использую команду predict в SPL. Это команда для фильтрации Калмана, вы можете проверить ее, нажав кнопку «Показать SPL» на панели «Временной ряд прогноза».

Измените метод на LLP и нажмите «Прогноз».

Что ж, неплохо. Основные сезонные профили (например, большой спад после Нового года) фиксируются и предсказываются почти идеально.

В России продленный новогодний праздник. Он начинается 1 января и длится около 8–10 дней (фактическая продолжительность варьируется от года к году). Он показывает, что активность пользователей во многих областях в те дни намного меньше, чем в другие дни.

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

Выброс с февраля 2017 г. повторяется в прогнозе, но выпадение с мая 2016 г. - нет. Таким образом, похоже, что фильтр Калмана с алгоритмом LLP переоценивает значения последнего периода (в нашем случае последних 365 дней) и не обращает внимания на соответствующие значения предыдущих периодов.

Такая же ситуация и с разгаром сезона в канун Нового года.

Однако такая особенность фильтрации Калмана не делает этот прогноз полностью неадекватным. Это может быть полезно, если мы действительно хотим полагаться только на последний период данных. Например, мы собираемся спрогнозировать количество входов в систему на неделю на основе данных за предыдущие недели только для обнаружения критических проблем в режиме реального времени. Если количество входов в систему заметно уменьшается, это, вероятно, означает некоторые проблемы с доступностью сервера аутентификации или что-то в этом роде. Для этого мониторинга мы можем создать простой и точный прогноз и просто сравнить новые данные с границами доверительного интервала.

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

| inputlookup daylogins.csv 
| timechart span=1d fixedrange=f max(daylogins) as daylogins 
| predict "daylogins" as prediction algorithm="LLT" future_timespan=365 lower"95"=lower"95" upper"95"=upper"95" 
| eval daylogins = case(daylogins < 'lower95(prediction)', 'lower95(prediction)', daylogins > 'upper95(prediction)', 'upper95(prediction)', 1=1, daylogins) 
| eval season = daylogins / prediction 
| predict "season" as season_prediction algorithm="LLP" future_timespan=365 period=365 lower"0"=lower"0" upper"0"=upper"0"
| eval prediction = prediction * season_prediction
| table _time, daylogins, prediction
| eval prediction = if(isnull(daylogins), prediction, null)
| where _time<strptime("2019-01-01", "%F")

Выглядит неплохо. Обратите внимание, что я наконец реализовал этот прогноз на чистом SPL без графического интерфейса помощника ML Toolkit. Итак, я могу вставить этот поиск в любую панель управления любого приложения (просто позаботьтесь о разрешениях на объекты знаний). Единственный параметр, который мне нужно указать, - это период сезонной составляющей (т.е. максимальный сезонный период в случае множественной сезонности). Вы можете разрешить пользователю указывать этот параметр на панели управления через простое текстовое поле ввода со значением по умолчанию 365. Также возможно вычислить максимальный сезонный период автоматически, используя преобразование Фурье или анализирующую функцию автокорреляции (мы поговорим об этом чуть позже. , Думаю).

Продолжение следует…

Сделаем краткий обзор фильтра Калмана в Splunk.

  • Это простой и полезный инструмент для прогнозирования временных рядов.
  • Прогноз можно легко создать с помощью одной команды SPL, не настраивая тонны параметров.
  • Фильтр (по названию) хорош для сглаживания зашумленных временных рядов.

Но эта простота означает отсутствие гибкости.

  • Вы вообще не можете контролировать сезонные периоды. В случае множественной сезонности можно полагаться только на внутренние алгоритмы фильтра.
  • Сезонный прогноз слишком мало учитывает значения за пределами последнего периода.
  • Нет никакого параметра, такого как «коэффициент сглаживания» для настройки «чувствительности к шумоподавлению». Поэтому фильтр иногда выполняет очень агрессивное сглаживание, что приводит к потере ценной информации.

Что ж, давай назовем это ночью. В следующей части рассмотрим более подробно ARIMA в Splunk. Будьте на связи!