Обзор проекта

В этом проекте я использую статистику, визуализацию и контролируемое обучение (то есть глубокую нейронную сеть), чтобы понять взаимосвязь между погодой, датой и потреблением энергии в Калифорнии. Самая эффективная модель, найденная с помощью KerasTuner, прогнозирует суточную потребность в энергии со среднеквадратичной ошибкой, которая составляет 6,3% от средней дневной потребности в энергии. Обнаружено, что глубокая нейронная сеть превосходит наивное усреднение исторической потребности в энергии. Полную кодовую базу можно найти на Github, хотя ключевые фрагменты включены в этот пост.

Оглавление

Фон

Благодаря усовершенствованию технологий использования возобновляемых источников энергии предпринимаются усилия по модернизации электрической сети Калифорнии. Калифорнийская коммунальная компания Southern California Edison недавно выпустила белую книгу, в которой обсуждается, как энергосистема должна измениться, чтобы поддержать цели Калифорнии по сокращению выбросов парниковых газов. В нем они заявляют, что сети нужны достижения в области прогнозной аналитики, чтобы реагировать на изменения нагрузки, поскольку проблемы с электроснабжением станут более распространенными и сложными для решения.

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

Сбор данных

После непродолжительного поиска в Интернете я наткнулся на два веб-сайта с общедоступными бесплатными данными, которые мне понадобятся для изучения этого вопроса. Двум веб-сайтам потребуются разные подходы к веб-скрейпингу. Онлайн-данные NOAA о климате содержит исторические данные о температуре и поддерживает API, который, как я ожидал, сделает поиск данных довольно простым. Калифорнийская энергетическая база данных, доступная через California Independent System Operator (CA ISO), потребует более сложного подхода к веб-скрейпингу, который включает автоматические щелчки мышью по календарю. Я начал с того, что взялся за более сложную из двух задач — энергетические данные.

Получение данных об энергопотреблении

Поскольку CA ISO поддерживает одну из крупнейших в мире электросетей и делает их данные доступными для общественности, спрос на энергию в Калифорнии находится в центре внимания этого проекта. Веб-сайт CA ISO позволяет пользователям загружать ежедневные данные об энергопотреблении с шагом 5 минут в течение 24 часов. Можно получить доступ к историческим данным, начиная с апреля 2018 года. Существует два типа данных о спросе на энергию, которые можно запросить: спрос и чистый спрос (спрос за вычетом энергии ветра и солнца). Спрос используется в качестве меток данных, тогда как чистый спрос для этого проекта не анализируется.

Ручная загрузка CSV-файла за каждый день заняла бы очень много времени, поэтому для извлечения данных об энергопотреблении используется подход веб-скрейпинга. Макет веб-страницы спроса на энергию содержит дату с раскрывающимся меню, где пользователь может щелкнуть календарь, чтобы получить доступ к другой дате. Зная, что мне потребуется автоматическое взаимодействие с браузером, чтобы нажимать кнопки календаря, я поискал в Интернете примеры похожих задач веб-скрейпинга.

К счастью для меня, в 2019 году Кен Фрайс опубликовал Medium Post, в котором описал, как собирать данные об электроэнергии с веб-сайта Калифорнийской организации ISO. Я смог использовать его код с небольшими изменениями.

В подходе Кена для автоматизации извлечения данных использовались Selenium WebDriver API и ChromeDriver. WebDriver эмулирует взаимодействие пользователя с браузером, что идеально подходит для автоматизации выбора дат в календаре. Обратите внимание, что для этого подхода необходим загруженный ChromeDriver, как указано в строке 9 кода ниже.

Сначала определите диапазон для очистки и создайте список дат в формате ММ/ДД/ГГГГ.

Затем определите функции для выбора данной даты на веб-сайте и загрузите CSV-файл для этой даты.

Добавьте строку состояния для отслеживания хода цикла и выполнения извлечения данных.

Составление необработанных данных о спросе на энергию

Получив необработанные данные об энергии из CA ISO, следующим шагом будет их компиляция и организация в DataFrame pandas.

Каждый файл CSV содержит необработанные данные в формате, показанном ниже:

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

Создается DataFrame, в котором есть столбец для даты и столбец для ежедневного потребления энергии. Работая с одним CSV-файлом, я тестирую фрагменты кода, чтобы выбрать соответствующую информацию за один день и добавить ее в DataFrame. Затем используется цикл for, чтобы воспроизвести этот процесс для всех 1501 CSV-файлов энергопотребления (вручную помещенных в каталог energy_demand_data). Модуль glob используется для возврата списка всех файлов CSV в каталоге.

После выполнения цикла for ежедневная потребность в энергии сохраняется в одном кадре данных (master_df).

Все выглядит так, как ожидалось. Количество строк в DataFrame равно количеству загруженных файлов, поэтому каждая дата встречается в DataFrame ровно один раз. В качестве еще одной проверки, диапазон дат — это то, что было указано в парсинге.

Получение данных о погоде

Калифорния огромна, и погода в южной части штата часто сильно отличается от погоды в северной части. Например, см. этот недавний твит от доктора Суэйна о погоде в Калифорнии в мае 2022 года:

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

Первоначально были выбраны семь лучших населенных пунктов Калифорнии. Однако из-за близости Лонг-Бич к Лос-Анджелесу (Лос-Анджелес) станция Лонг-Бич впоследствии была заброшена. Вместо этого Лос-Анджелес был разделен на два региона, внутренний и прибрежный, чтобы учесть большую численность населения Лос-Анджелеса и географическую изменчивость. Например, когда я пишу это, во внутренней части Лос-Анджелеса максимальная температура составляет 95 °F, а в прибрежной — 74 °F.

Учитывая большой географический охват Калифорнии и различные погодные условия, важно ориентироваться в местах. Используя GeoPandas и широту/долготу каждой метеостанции, наносятся на карту местоположения метеостанций. Следует отметить, что внутренние станции Сакраменто, Фресно и Лос-Анджелес находятся намного дальше от побережья, чем другие станции, поэтому я ожидаю, что их погода будет иметь другую корреляцию с метками энергопотребления, чем в других местах.

Доступ к историческим данным о погоде можно получить из веб-сайта NOAA Climate Data Online через API, который можно использовать для запроса данных. Для использования этого API необходимо запросить токен веб-сервиса. Получив доступ к веб-службам CDO NCDC, базовый URL-адрес можно изменить для запроса определенных наборов данных. Пост о сборе данных о погоде от Ritvik Kharkar был полезным ресурсом для этой части поиска данных, поскольку документация по API, предоставленная NOAA, скудна.

Используя инструмент Найти станцию NOAA, я нашел станции в интересующих регионах. Сначала меня интересовало среднесуточное значение температуры для каждой станции, но вскоре я понял, что на многих станциях отсутствуют полные данные. После попытки определить станции, которые имели высокий процент покрытия данными для моего диапазона дат, я пришел к выводу, что мне нужно переключиться со среднесуточного значения температуры на минимальное и максимальное значение температуры для каждого дня. На большинстве станций, которые я смотрел, не регистрировались среднесуточные температуры. Тем не менее, мне удалось найти 7 местоположений станций, которые имели >99% покрытия данных для значений минимальной/максимальной температуры в моем диапазоне дат. В конечном итоге это оказалось выгодным изменением планов, поскольку оно дало две разные характеристики погоды, и одна из них оказалась более коррелированной с потребностью в энергии, чем другая.

API NOAA имеет максимальное ограничение в 1000 элементов на вызов, поэтому он вызывается один раз в год в интересующем диапазоне дат.

Длина списка min_temp_values не равна длине списка max_temp_values. Поэтому я снова запущу слегка измененный скрипт для неполного списка (min_temp_values).

Создаются два DataFrames, один для данных о минимальной температуре и один для данных о максимальной температуре. Я гарантирую, что извлечение данных прошло по плану, все 7 местоположений станций включены в данные, а временные параметры извлекаются из каждой станции за каждый день в диапазоне дат.

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

Объединение характеристик погоды с метками энергопотребления

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

  • Формат даты различается между двумя DataFrames. Тот же формат необходим для объединения столбца даты в pandas.
  • Данные о температуре заканчиваются за несколько дней до даты окончательного энергопотребления (заканчивается 14.05.2022). Возможно, данные о температуре архивируются с небольшой задержкой. Недостаток данных можно устранить с помощью внутреннего слияния, при котором строки без полных данных будут удалены.
  • Для нескольких дат отсутствуют некоторые данные о температуре по крайней мере с 1 станции. Хотя недостающие данные можно устранить сейчас, я сделаю это позже в разделе очистки данных.

Затем кадры данных погоды и энергии объединяются.

Со всеми необработанными данными в одном DataFrame пришло время для некоторого исследовательского анализа данных!

Аналитика данных до модели

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

Я использую Seaborn в сочетании с Matplotlib для визуализации данных. См. проект Репозиторий GitHub для кода каждой визуализации.

Исследовательский анализ данных

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

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

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

df['Day'] = df['Date'].dt.day_name() #DateTime method

day_order = ['Monday', 'Tuesday, 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']

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

Очистка данных

Для достижения наилучших результатов визуализации и моделирования важно иметь значимые высококачественные данные. Различные функции/метки проверяются на наличие отсутствующих или выдающихся данных, а функции разрабатываются таким образом, чтобы помочь понять данные.

Глядя на среду на рис. 11, видно, что в данных есть очевидный выброс. Выброс также появляется на рис. 9, где наблюдается большой провал около 4–10–2018 гг.

Выполнение расчета z-показателя позволяет выявить выбросы в данных об энергопотреблении; выбросами считаются все значения, превышающие 3 стандартных отклонения от среднего значения.

Из 10 472 значений энергии 42 из них имеют абсолютный показатель z > 3. Важно подчеркнуть, что в наборе данных об энергии не 10 472 дня, а 1498 дней, но большинство из этих дней имеют 7 показания температуры станций для них, чтобы они встречались в наборе данных 7 раз. Это означает, что 6 дней являются выбросами.

Вызывая outliers.index.values, мы можем определить индексы значений выбросов и получить DataFrame дат для этих значений. Ручная проверка этих дат на веб-сайте CA ISO показывает, что только 11 апреля 2018 года имеются неполные данные. Вполне вероятно, что нетипичное событие вызвало более высокий, чем обычно, спрос на энергию для других дат, 24–25 июля 2018 г. и 17–19 августа 2020 г., что привело к их высокому показателю z. Эти события могли быть волнами жары, поскольку максимальная температура в некоторых местах в те дни превышала 100.

Чтобы учесть отсутствующие данные на 11 апреля 2018 г., выполняется простое вменение путем усреднения энергопотребления на две смежные даты.

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

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

Зная, что первый и последний годы в наборе данных являются неполными, возможность разделения по годам может быть важной. Кроме того, мне интересно посмотреть, как спрос изменился за эти годы. Функция года добавляется с помощью атрибута year datetime.

Как в 2020, так и в 2021 году распределение спроса на энергию больше, чем в 2019 году. Примечательно, что, несмотря на сбои, вызванные COVID-19 в 2020 году, спрос на энергию в 2021 году примерно равен спросу в 2020 году. Однако, если мы разобьем годовые данные на месяц, влияние COVID-19 заметно в апреле 2020 года.

Готовясь отобразить данные о погоде, я привожу в порядок DataFrame с последовательным форматированием названий местоположений станций и проверяю наличие нулевых значений. Я не ожидаю нулевых значений на основе используемых внутренних слияний, и быстрый df.isna().sum() подтверждает это. Тем не менее, для некоторых дней отсутствуют значения температуры, как мы видели во время поиска данных. В этих комбинациях даты/станции просто нет строк данных.

На этом этапе я трачу нетривиальное количество времени на подготовку к визуализации отсутствующих комбинаций даты/станции с помощью тепловой карты. Сложно найти способ заполнить 0/1 с для каждой даты/станции, чтобы указать, существуют ли данные в DataFrame. Полный код этой части проекта можно найти в Notebook II в моем репозитории GitHub. Он довольно длинный и тангенциальный, поэтому я просто резюмирую его здесь:

  • Создается список дат, в которых отсутствует хотя бы одно временное значение.
  • Создается новый кадр данных с отсутствующими датами в качестве индексов и столбцами в качестве местоположений станций.
  • В основной DataFrame добавляется временная строковая колонка даты.
  • Создается функция для заполнения нового кадра данных нулями и единицами в зависимости от того, имеет ли эта комбинация даты/местоположения в основном кадре данных показания температуры.
  • Функция запускается для каждой станции, в результате чего создается кадр данных, в котором даты с отсутствующими данными являются индексами, а станции — столбцами. Значения DataFrame равны 0 и 1, чтобы показать, существуют ли данные для этой комбинации станции/даты.

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

Желтый цвет указывает на отсутствие данных. Во всех городах отсутствуют данные о температуре на 28 февраля 2018 года, а затем в нескольких городах отсутствуют данные о температуре на другие даты. В Сан-Хосе отсутствует больше всего данных.

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

Визуализация данных

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

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

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

Чтобы более подробно визуализировать взаимосвязь между минимальной температурой и потреблением энергии, я строю диаграмму рассеивания потребления энергии в зависимости от минимальной температуры.

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

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

Прибрежные погодные районы имеют более узкое распределение минимальной температуры, чем внутренние районы (Фресно, Сакраменто и внутренние районы Лос-Анджелеса) (географическое изображение см. на рис. 6).

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

Во Фресно самая сильная корреляция между потреблением энергии и температурой, особенно при минимальной температуре. Учитывая, что Фресно — самая удаленная от суши станция, а внутренние температуры Лос-Анджелеса также довольно хорошо коррелированы, места с более экстремальными максимумами и минимумами, по-видимому, больше всего коррелируют с потреблением энергии.

Я вкратце изучил эффект объединения внутренних и прибрежных регионов Лос-Анджелеса, чтобы увидеть, улучшилась ли корреляция — но это не так. Прибрежный район Лос-Анджелеса слишком плохо коррелирует с потребностью в энергии, что может быть связано с тем, что большая часть населения региона живет не прямо вдоль побережья.

После осмотра кривая спроса на энергию в Калифорнии отслеживает минимальную температуру во Фресно в течение большей части года.

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

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

Используя столбец сезона в качестве hue, можно создать совместный график Seaborn, который позволяет визуализировать сезонное влияние на потребление энергии и минимальные температуры.

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

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

Могут происходить две вещи:

  • Зимой погода может в меньшей степени предсказать спрос на энергию, потому что люди используют газовые отопительные печи, которые не берут электричество из сети.
  • Летом из-за большого географического охвата Калифорнии температура сильно варьируется, и могут быть важны дополнительные данные, такие как средний размер дома, основные профессии по регионам и их потребность в энергии, а также школьные расписания.

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

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

Приведенный выше код добавляет шесть новых столбцов в DataFrame:

Затем можно построить графики циклических временных характеристик, чтобы визуализировать их кривые.

Следует отметить, что я мог бы также выполнить циклическое кодирование для дней в году (1–365), но поскольку временные рамки составляют всего ~3,5 года, каждый день будет встречаться только 3 или 4 раза.

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

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

Подготовка данных

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

Подготовка DataFrame к моделированию

Функции sin/cos для месяца и дня недели сохранят всю информацию о дате, поэтому столбцы даты, дня, сезона и месяца можно опустить. Для каждого местоположения станции создаются фиктивные переменные, при этом первый столбец удаляется, чтобы предотвратить повторение данных в DataFrame.

Полученная голова DataFrame, подготовленная для моделирования, выглядит следующим образом:

Обучение тестовому сплиту

Для данных временных рядов, если разбивка тестового обучения рандомизирована, модель может научиться интерполировать между соседними точками, а не учиться на основе функций. Поэтому для тестовой выборки я использую данные за последний год, а не случайную выборку. С 7 местоположениями станций и каждым местоположением, имеющим 1 строку данных в день, последние 2555 строк в DataFrame представляют последний год данных и будут тестовым набором. Общая длина DataFrame составляет 10 472, поэтому тестовый набор представляет примерно 24 % данных.

Нормализация данных

Когда входные переменные имеют разные единицы измерения и, следовательно, масштабы, полезно нормализовать данные. Линейное масштабирование данных помогает многим моделям машинного обучения работать лучше за счет одинакового учета влияния всех функций и стабилизации процесса обучения. С помощью MinMaxScaler данные нормализуются в диапазоне 0–1.

Машинное обучение

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

Определение модели

Я использую модель Keras Sequential, потому что она проста и хорошо подходит для задач, где будет использоваться только один входной и выходной тензор. Функция потери среднеквадратичной ошибки используется, поскольку метки непрерывны (проблема регрессии), а для выполнения процедуры оптимизации используется алгоритм Адама (современное расширение стохастического градиентного спуска).

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

Я использую EarlyStopping, чтобы модель останавливала обучение, когда потеря проверки больше не улучшается.

Подгонка модели

Модель подходит, используя вышеуказанную архитектуру и раннюю остановку.

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

Через 125 эпох модель остановилась. Потеря теста и проверки следуют аналогичной тенденции и хорошо себя ведут.

Эта модель дает среднеквадратичную ошибку (RMSE) 5,42 x 10⁵ (среднее значение метки = 7,17 x 10⁶) и показатель объясненной дисперсии 0,74 (мера несоответствия между моделью и фактическими данными, наилучший возможный показатель равен 1,0). и более низкие значения хуже).

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

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

Изучение пакетной нормализации

Пакетная нормализация стандартизирует входные данные для слоя в нейронной сети глубокого обучения, масштабируя данные так, чтобы они имели среднее значение 0 и стандартное отклонение 1. Важно отметить, что пакетную нормализацию не следует использовать с выпадающими слоями (они могут сделать статистику стандартизации слишком зашумленной). Я удаляю отсева и оцениваю производительность модели с применением пакетной нормализации к выходным данным первого скрытого слоя.

Эта модель улучшает предыдущую, она дает RMSE = 4,76 x 10⁵ и показатель объясненной дисперсии 0,78.

Оптимизация гиперпараметров с помощью KerasTuner

Используя описанные выше ручные методы проб и ошибок, становится ясно, что количество слоев модели, количество узлов на слой, выпадающие слои и нормализация пакетов значительно влияют на производительность модели. Подходящая модель была найдена путем ручной настройки гиперпараметров, но для дальнейшей оптимизации гиперпараметров можно использовать KerasTuner, фреймворк оптимизации. У Люка Ньюмана есть очень полезный пост об использовании KerasTuner with TensorFlow.

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

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

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

  • «num_layers» = 2–6 (соответствует диапазону скрытых слоев 1–5)
  • «единицы» = 7–807 с размером шага 50 (количество узлов в слое)
  • «BatchNorm1 и «Dropout1» как логические параметры, которые являются взаимоисключающими (например, если BatchNorm1 имеет значение «Истина», то Dropout1 не имеет значения).
  • «скорость_обучения» = 0,01, 0,001, 0,0001

Оптимальные результаты гиперпараметров запрашиваются и печатаются:

KerasTuner определил, что оптимальной архитектурой модели является: 4 скрытых слоя, скорость обучения = 0,01, большое количество узлов относительно входных данных (757, 757, 657, 107 против 13 входных данных) и одна пакетная нормализация после второго скрытого слоя. . Эта архитектура используется для подгонки данных.

Оценка модели

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

Общая эффективность модели

Кривая обучения модели выглядит великолепно. Это было верно для большинства протестированных моделей. RMSE составляет 4,50 x 10⁵, что является скромным улучшением по сравнению с моделью, настроенной вручную, а показатель объясненной дисперсии составляет 0,80. Среднесуточная потребность в энергии составляет 7,17 x 10⁶ при стандартном значении 1,03 x 10⁶. RMSE составляет 6,3% от среднесуточной потребности в энергии.

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

Производительность модели (ежемесячно)

Визуализация данных предварительного моделирования показала, что корреляция между данными о погоде и энергии наиболее сильна в весенние и осенние месяцы. Поэтому я хочу отображать RMSE ежемесячно и смотреть, как он меняется в зависимости от месяца. Это сложно, потому что значения y_test не имеют своей даты, связанной с ними, но у них есть индексы, которые можно использовать для возврата к дате, поскольку во время разделения тестов на поезде было установлено значение false.

Следующие столбцы добавляются в DataFrame (при подготовке к построению): прогнозируемая метка, фактическая метка, месяц, остаток в квадрате.

Приведенный выше код приводит к DataFrame с заголовком:

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

rmse_bymonth = np.sqrt(predictions_df.groupby('month')['residual_squared'].mean())

Показано в виде гистограммы:

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

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

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

Затем я хочу визуализировать ежемесячные прогнозируемые значения модели в сравнении с фактическими значениями. Это можно сделать с помощью ящичковой диаграммы, разделенной оттенком, со всеми значениями энергопотребления (как прогнозируемыми, так и истинными) в одном столбце, а во втором столбце указано, являются ли они прогнозируемыми или истинными значениями (названными «Тип»). Для этого я создаю два меньших фрейма данных, по одному для каждого типа значения, объединяю их, а затем строю фрейм данных, используя блочную диаграмму Seaborn с hue='Type'.

На этой диаграмме средний спрос на энергию сравнивается с прогнозируемым средним спросом в месяц.

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

Производительность модели (ежедневно)

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

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

Поскольку 2020 год был високосным, все значения day_of_year были бы смещены на 1 с марта, если бы не были скорректированы. Чтобы учесть это, у меня есть функция, настроенная на (1) вычитание 1 из всех дней с 1 марта по 31 декабря 2020 г. (2) возвращение високосного дня в виде произвольного значения 500. Високосный день в конечном итоге удаляется из DataFrame .

Используя training_days.groupby('Day of Year').mean(), я определяю среднесуточную потребность в энергии для данного дня в году. Это простой способ прогнозирования спроса на энергию, который не принимает во внимание год или погоду, а учитывает исторический спрос на энергию в этот день.

Затем я повторяю этот процесс создания столбца дня года для тестовых данных (последние 2555 значений в DataFrame), чтобы можно было сравнить истинные значения с историческими прогнозами.

Создается DataFrame, который объединяет фактические ежедневные значения энергии из DataFrame «test_days», исторические прогнозы из DataFrame «training_days» и прогнозируемые значения нейронной сети.

RMSE рассчитывается для каждого дня, а остатки отображаются на диаграмме рассеяния.

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

Этот график KDE показывает, что прогнозы, сгенерированные нейронной сетью, имеют меньшее остаточное распределение, чем исторические прогнозы, сгенерированные средним значением. Меньшие остаточные значения указывают на то, что прогнозы более точны, поэтому желательно иметь как можно большую часть остаточной совокупности как можно ближе к 0.

Среднесуточная среднеквадратическая ошибка составляет 3,14 x 10⁵ при использовании значений, предсказанных нейронной сетью, по сравнению со среднеквадратичной ошибкой 4,79 x 10⁵, если для прогнозирования энергии используется историческое среднее значение за этот день. Эти значения RMSE представляют 4,4% среднего суточного потребления энергии и 6,7% соответственно. Важно отметить, что среднесуточный RMSE здесь отличается от глобального RMSE, указанного в начале оценки модели (6,3%), потому что указанный здесь RMSE представляет собой среднее значение RMSE каждого дня, поэтому каждый расчет RMSE здесь имеет п=1.

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

Выводы

Модели глубокого обучения могут успешно прогнозировать потребность Калифорнии в энергии по погоде и дате календаря. Самая эффективная модель, найденная с помощью KerasTuner, прогнозирует суточную потребность в энергии со среднеквадратичным отклонением, которое составляет 6,3% от средней дневной потребности в энергии. Модель наиболее точна для января-марта и наименее точна для июля, сентября и июня. Модель ML превосходит наивное предсказание, когда исторические метки усредняются.

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

В будущем я планирую оценить, как эта модель соотносится с прогнозами энергии на следующий день, доступными на веб-сайте CA ISO. В любом случае, важно иметь возможность прогнозировать потребность в энергии на будущие даты, когда известны минимальные/максимальные температуры, которые должны простираться значительно дальше в будущее, чем прогнозы следующего дня, которые делает CA ISO.