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

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

Этот пост прямо здесь продолжает это путешествие. Мы использовали некоторые подробные данные о потреблении для определения групп потребителей, и теперь у нас, возможно, есть несколько новых клиентов, которые были отнесены к этим группам на основе известной нам информации о них (какой тип бизнеса они представляют, в каком городе они расположены, … ).

Теперь нам нужно спрогнозировать, сколько электроэнергии они будут использовать в следующем году, и мы хотим знать, что при максимально возможной детализации — в Великобритании это будет отдельно для каждого получаса дня. Поскольку этот клиент был отнесен к определенной группе потребителей, мы можем использовать любые исторические данные о потреблении, которые у нас есть от всех других клиентов в этой группе. Итак, что мы на самом деле хотим сделать сейчас, так это построить модель машинного обучения, которая как бы «усредняет» все эти доступные данные (т. е. находит наиболее вероятное потребление за заданные полчаса в заданный день) и использует их для прогнозирования потребления будущий период.

На этот раз я позаботился о том, чтобы сохранить весь код в довольно чистом блокноте Jupyter, который сопровождается фактическими данными, которые я использовал для создания рисунков, показанных ниже, так что не стесняйтесь проверить его и поэкспериментировать с ним самостоятельно!

Компоновка данных и разработка функций

Данные, с которых мы начинаем, довольно просты — один кадр данных, в котором перечислено (большое) количество нормализованных измерений потребления электроэнергии с временными метками для ряда счетчиков, и второй кадр данных, который определяет группу потребителей (кластер), к которой принадлежит каждый счетчик:

Мы, конечно, не можем просто бросить это в такой алгоритм машинного обучения. Сначала нам нужно выбрать только данные, принадлежащие одному и тому же кластеру, а затем мы хотим создать некоторые признаки, которые мы считаем хорошими (информативными и независимыми) свойствами, подходящими для того, чтобы позволить алгоритму машинного обучения «узнать» характеристики группы клиентов, принадлежащих к этому кластеру. В этом случае столбец usage — это, по сути, то, что мы хотим предсказать, поэтому у нас остаются meter_id и timestamp в качестве основы для создания признаков, если только у нас нет дополнительной информации, которую мы могли бы добавить (в этом примере мы этого не делаем).

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

Остается только timestamp для создания значимых функций. В данном контексте это имеет смысл — окончательная модель должна возвращать единую (нормализованную) кривую потребления для будущего периода, которая объединяет всю информацию, которую можно извлечь из исторических данных о потреблении все счетчики в этой группе потребителей. Мы сгруппировали эти счетчики, зная, что их модели потребления очень похожи.

Итак, что мы можем получить от timestamp? Давайте быстро подумаем о том, какие переменные, связанные со временем, обычно подходят для описания потребления электроэнергии:

  • Время года. Обычно у нас есть сезонная зависимость. Для частного рынка основными факторами, определяющими эту изменчивость, являются, например, использование отопления в холодное время года и кондиционирования воздуха в теплое время года. В нашем примере мы создаем два циклических признака, кодирующих информацию о сезоне (точнее, годовом ходе) с помощью синуса и косинуса,
    df["year_sin"] = np.sin(2 * np.pi * doy / year_days) и
    df["year_cos"] = np.cos(2 * np.pi * doy / year_days)
    с doy в качестве дня года и year_days в качестве дня года. общее количество дней в данном году. Этот способ кодирования сезонности позволяет избежать разрыва при смене года, что всегда является хорошей практикой.
  • Время суток. Естественно, потребление энергии обычно имеет четкий дневной график. Создаем циклические признаки так же, как и для времени года.
  • День недели. Потребление обычно также различается в разные дни недели, хотя это, вероятно, не относится ко всем отраслям. В некоторых случаях можно различать только выходные и будние дни, но, учитывая большое количество данных, которые у нас есть для этого примера, мы просто создаем категориальные признаки для всех семи дней недели. с использованием горячего кодирования. Обратите внимание, что в этом примере используется дополнительный вход календаря для определения государственных праздников, которые имеют 1 в столбце weekday_99 вместо стандартных столбцов дней недели.

В итоге мы получаем таблицу функций, которая выглядит так:

Каждая строка содержит вектор признаков, а столбец usage из исходной входной таблицы содержит связанные метки/цели. Это то, что часто называют «аккуратными данными», готовыми для использования в модели машинного обучения.

Настройка модели и обучение

Теперь, когда мы знаем, как выглядят наши данные, пришло время выбрать подходящий алгоритм машинного обучения. Поскольку у нас есть метки для всех векторов признаков, нам нужен контролируемый алгоритм обучения; и в конечном итоге мы хотим, чтобы модель предсказывала числовое значение (потребление электроэнергии), а не какое-то членство в группе, так что это явно регрессионная задача.

С этой задачей справится известная и любимая многими модель LightGBM. Здесь мы придерживаемся довольно простого подхода — просто разделяем функции и метки на обучающие и проверочные наборы, используя scikit-learn’s train_test_split и загружаем данные в модель LightGBM с практически готовыми настройками:

Давайте быстро посмотрим, что LightGBM делает с этими данными: LightGBM — это «фреймворк для повышения градиента, использующий алгоритмы обучения на основе дерева», как говорится на их веб-сайте, но что это значит? Я предполагаю, что у вас есть представление о том, что такое дерево решений, если вы все еще читаете этот момент, так что давайте начнем отсюда. Начиная с полного набора обучающих данных, дерево решений строится путем последовательного разделения/разветвления этих данных на подмножества на основе векторов признаков образцов. После выполнения определенного условия (выборки каждого листа достаточно похожи или выполнено максимальное количество листьев или разбиений…) дерево считается «законченным» — его можно использовать для формирования прогноза для любого ранее невиданного вектора признаков. следуя ветвям в соответствии с условиями ветвления и используя известные образцы в последних листьях дерева.

Конечно, эта модель довольно проста и может быть значительно улучшена. Можно использовать целый ансамбль деревьев, каждое из которых создано с разными подмножествами обучающих данных, и усреднять результаты — это то, что мы знаем как случайный лес. Еще более эффективным методом оптимизации деревьев решений является повышение градиента: мы начинаем с обучения одного дерева и используем другое дерево для исправления его недостатков. На практике это означает, что второе дерево обучается на остатках первого дерева (математически это хорошо обрабатывается с помощью градиента, отсюда и часть повышения градиента), и прогноз получается путем сложения двух деревьев. ' Результаты. Конечно, этот процесс можно продолжать столько итераций, сколько необходимо — в этом случае мы позволяем алгоритму добавлять деревья решений до тех пор, пока не будет добавлено десять деревьев, не приводя к улучшению производительности проверочного набора ( early_stopping_rounds=10), чтобы предотвратить переоснащение. Чтобы получить представление о том, как выглядят эти деревья, посмотрите ниже 10-е дерево, добавленное в нашу модель:

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

Оценка производительности

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

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

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

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

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

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

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

Не стесняйтесь оставлять комментарии, если у вас есть идеи по улучшению этой логики или если у вас есть какие-либо вопросы! Если вы нашли эту статью интересной и хотели бы сами изучить новые подходы к науке о данных с служебными данными, не стесняйтесь проверить Вакансии в Горилле — в данный момент мы, например, ищем Инженер данных Python, чтобы работайте над такими вещами!