Merlion Framework или как упростить работу с временными рядами
Вспомним фразу знаменитого физика-теоретика с Марковым Никитой
Единственная причина для существования времени — чтобы всё не случилось одновременно.
В нашем мире время является незаметным четвертым измерением (или временным рядом), по оси которого, можно упорядочивать разные события.
Временной ряд – это набор данных, описывающих изменения какой-либо переменной во времени.
Задача анализа и предсказания временных рядов остаётся актуальной для бизнеса так как для успешного планирования возникает необходимость прогнозирования, например, следующих показателей:
· спрос на определенные продукты/услуги;
· нагрузка на контактный центр или сервера компании;
· количество новых пользователей/загрузок для приложения.
Наиболее популярные подходы для предсказания временных рядов делятся на:
· статистические:
o ARIMA (AutoRegressive Integrated Moving Average);
o ETS (Error, Trend, Seasonal);
o Prophet;
o Exponential Smoother.
· основанные на методах машинного обучения:
o Vector AutoRegressive;
o DeepAR;
o Transfromer;
o RandomForestForecaster.
Так какой же метод выбрать для решения задачи?
Преимущество статистических методов заключается в относительной простоте моделей, что делает их более интерпретируемыми и помогает исследовать зависимости между переменными. Однако модели машинного обучения гораздо лучше справляются с описанием динамики более сложных нелинейных процессов.
Почему бы просто не попробовать каждый из этих методов?
Для этого придётся устанавливать много библиотек и готовить по-разному данные для обучения и предсказания каждой модели.
Есть ли какая-то одна библиотека, которая облегчит задачу предсказания временных рядов?
Да, такая библиотека уже существует и называется Merlion Framework.
Краткий обзор библиотеки Merlion
Merlion – это библиотека для анализа временных рядов, написанная на языке Python. Она предоставляет комплексную платформу машинного обучения, которая включает:
• загрузку и преобразование данных в удобный формат хранения временных рядов;
• построение и обучение моделей для предсказания и детекции аномалий;
· простые в использовании ансамбли;
· распределенные вычисления с иcпользованием Spark;
• последующую обработку выходных данных модели для уменьшения ошибок и повышения интерпретируемости результатов;
• построение пайплайнов для оценки производительности модели.
Цель этой библиотеки – предоставить инженерам и исследователям универсальное решение для быстрой разработки моделей и их сравнения.
С полным списком возможностей можно ознакомиться взглянув на таблицу сравнения с другими библиотеками для анализа временных рядов, взятую из github-репозитория библиотеки. Там же есть и инструкция по установке.
Сравнительный анализ похожих библиотек по возможностям
По набору возможностей c Merlion могут конкурировать Kats и darts.
Kats предоставляет схожий функционал, но не поддерживает модели архитектуры Transformer, как и возможность использования экзогенных параметров в предсказателях (переменных, которые не объясняются другими переменными в модели, например, погода).
darts предоставляет богатый выбор моделей, возможности для оценки предсказаний, проигрывая разве что в отсутствии функциональности для распознавания change points.
Архитектура и основные структуры данных
Merlion состоит из следующих основных пакетов:
· utils – содержит модули, предоставляющие структуру данных для работы с временными рядами;
· transform – предоставляет функциональность для преобразования временных рядов;
· models – содержит реализации готовых моделей для предсказания и поиска аномалий;
· evaluate – хранит метрики для оценки модели;
· post_process – даёт возможность обработать спрогнозированный временной ряд;
· spark – связующий модуль для работы с Apache Spark.
Начну работу с библиотекой сразу с практики. Для примера возьму простой датасет с kaggle. Он содержит информацию о траффике пешеходов и велосипедистов, двигающихся в направлении юга или севера мимо одного и того же светофора в Сиэтле. Информация обновляется с интервалом один час.
В чем проблема датасетов временных рядов?
Для того, чтобы «скормить» такой датасет на обучение какой-нибудь крутой нейросетке, его нужно подготовить. Допустим я хочу по двум предыдущим значениям предсказать третье, тогда необходимо пройтись окном размера два по нашей выборке и нарезать её на тренировочные образцы, содержащие подва элемента на вход модели (X) и один элемент как ожидаемое прогнозное значение (y).
Обычно на этом этапе возникает путаница с датами и размерами. К тому же если в результате экспериментов захочу предсказывать не по двум предыдущим значениям, а по трём, придётся заново подготавливать данные и подгонять датасет под ожидаемые моделью размеры.
Merlion решает эту проблему просто, предоставляя свою структуру для хранения временных рядов, которая заточена под работу с интерфейсом предсказательных моделей.
Создаю временные ряды
UnivariateTimeSeries наследуется от pd.Series и является основным строительным блоком в Merlion. Это специальная структура данных для хранения одномерного временного ряда и работы с ним.
Как создать?
UnivariateTimeSeries легко инициализировать из pd.Series или pd.Dataframe, в котором индекс единственной колонки (все-таки создаем одномерный временной ряд) должен указывать время наблюдения.
Что ещё может UnivariateTimeSeries?
Помимо всех унаследованных стандартных функций pd.Series, UnivariateTimeSeries предоставляет следующие фишки:
· разбить ряд на два по временной метке функцией bisect():
· выбрать строки датасета в промежутке между датами
uts.window("2014-01-01 00:00:00", "2014-01-01 06:00:00"):
Bisect и window облегчают выборку по времени, заменяя более громоздкие конструкции из pandas:
А как хранить многомерный временной ряд?
TimeSeries предоставляет функционал для работы с многомерными временными рядами и объединяет в себе несколько UnivariateTimeSeries.
Создать такую структуру можно из готового pd.Dataframe (как с множеством колонок, так и с единственной). Однако возникает ситуация, когда есть несколько одномерных временных рядов с разной частотой наблюдений, которые надо как-то объединить.
Для этого существует конструктор, принимающий словарь из UnivariateTimeSeries.
Функция Align поможет выровнять одномерные ряды, предоставляя разработчику выбор стратегий объединения наблюдений и заполнения пропусков.
Работа с моделями для предсказания
Merlion содержит богатый набор моделей под общим интерфейсом ModelBase, который пригодится для непосредственной работы с моделью:
· сохранение весов модели в файл;
· загрузка и инициализация из файла;
· получение информации о последнем обучении;
· получение информации о конфигурации модели.
Модели Merlion используются для двух типов задач временных рядов: обнаружение аномалий и предсказание.
В посте я рассмотрю задачу предсказания и, соответственно, буду работать с моделями под интерфейсом ForecasterBase, который предоставляет следующие основные функции:
· train – обучить модель на входных данных;
· forecast – получить предсказание;
· plot_forecast – изобразить на графике сравнение между предсказанным временным рядом и тестовыми данными;
· и др.
Чтобы создать Forecaster с какой-либо моделью внутри, необходимо создать соответствующий экземпляр Config, который будет передан в конструктор.
В данном случае ArimaConfig принимает параметры, влияющие на обучение модели. А экземпляр класса Arima предоставляет методы для запуска процесса обучения и построения прогноза.
Метрика MAE модели Arima равна 9.617.
График предсказания модели Arima на тестовой выборке. Синяя область визуализирует межквартильный диапазон (interquartile range).
Если захочу взять принципиально другой метод для предсказания, например, градиентный бустинг, я также легко смогу это сделать, просто инициализировав другую модель. Остальной код, который в последующем можно обернуть в функцию, останется без изменений, в этом и прелесть интерфейсов.
Метрика MAE модели градиентного бустинга равна 10.501
Предсказание на тестовой выборке
Что делать, если я хочу использовать модель, реализации которой нет в библиотеке?
Архитектура Merlion располагает возможностями к добавлению собственных моделей.
Схема зависимости DeepForecaster от nn.Module (базовый модуль для построения нейронных систем во фреймворке PyTotch)
Как видно, DeepForecaster является предком torch.nn.Module, что даёт возможность реализовывать нейронные сети в PyTorch и оборачивать их в удобную обертку DeepForecaster.
Ансамблирование
Ансамблирование – это метод в машинном обучении, цель которого объединить разные модели, обученные для решения одной и той же задачи. Полученные предсказания каждой модели обычно усредняются, и такая комбинированная оценка часто оказывается лучше предсказания каждой модели по отдельности.
Merlion позаботился об ансамблировании за пользователей и предоставляет два варианта как можно скомбинировать модели:
· ensemble — агрегирует предсказания каждой из моделей (медиана, среднее, максимум, средневзвешенное);
· selector — выбирает лучшую модель, основываясь на заданной метрике.
ForecasterEnsemble наследуется от класса ForecasterBase, что даёт возможность использовать его точно также, как и обычные модели выше.
Метрика MAE ансамбля равна 9.105
Результаты предсказаний на тестовой выборке ансамбля selector
Как видно, простое ансамблирование двух моделей Arima и LGBM помогло снизить MAE с 9.617 и 10.501 до 9.105.
Оценка
Расчёт метрик качества предсказаний средствами фреймворка
Класс ForecastMetric содержит следующие метрики:
· Mean Absolute Error (MAE);
· Mean Absolute Ranged Relative Error (MARRE);
· Root Mean Squared Error (RMSE);
· symmetric Mean Absolute Percentage Error (sMAPE);
· Root Mean Square Percent Error;
· Mean Absolute Scaled Error (MASE);
· Mean Scaled Interval Score (MSIS).
Выше я уже оценивал точность прогноза, но делал это только на части тренировочной выборки. Это не даёт уверенности в том, что при дообучении модели на новых данных, точность не упадёт. Поэтому в Merlion был реализован класс ForecastEvaluator, позволяющий проводить Rolling Cross Validation.
Это проверка, суть которой в постоянном расширении обучающей выборки за счёт старой тестовой, что позволяет убедиться, что модель не просто обучилась единожды подгонять прогноз под тестовую выборку, но и способна выдерживать дальнейшие обучения без сильной потери в точности уже на новых данных.
В ForecastEvaluatorConfig я задал частоту повторного обучения 24 часа, также можно задать и другие параметры, например, ограничить максимальный размер тренировочной выборки (например, если не захочу проверять на совсем старых значениях) или задать как часто будут делаться предсказания для проверки (что влияет на количество тренировок и конечно же на общее время выполнения).
Получается, я не единожды обучил на тренировочной выборке и проверил, а разбил тренировочную на несколько частей и оценивали каждый раз как меняются метрики, что позволило собрать больше данных о результате обучения. В данном случае такая проверка показала, что в результате обучения на порционно подаваемых данных, которые разделены по принципу Rolling Cross Validation, метрика MAE возрастает c 9.105 до 16.197. Из чего можно сделать вывод о снижении предсказательной способности.
Вывод
В посте был проведён лишь поверхностный анализ возможностей Merlion, полностью описать которые сложно даже за серия постов. Я убедился, что данное решение помогает упростить работу с временными рядами и предсказательными моделями. Становится неважно, работаю с нейронной сетью или простой ARIMA моделью, Merlion даёт возможность быстро попробовать разные варианты, при этом экономя драгоценное время на подготовку данных. Библиотека развивается в упрощении работы с временными рядами, например, появлением графического интерфейса со встроенными no-code autoML решениями. Набор возможностей перекрывает все остальные фреймворки. Из минусов – библиотека пока что требует уверенные знания Python т.к. потребуется нередко залезать в исходные коды (советую сразу работать в IDE), чтобы понять, что могло пойти не так, т.к. сообщения об ошибках иногда не наталкивают на скорейший путь к исправлению.
Также могу отметить разве что редкое упоминание в интернете, что я и пытаюсь исправить написанием поста.
Благодарю за прочтение, код из примеров вы сможете найти на github.