Использование линейной регрессии для прогнозирования производства возобновляемой энергии на основе данных о погоде в Германии в 2016 г.

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

Этот проект позволил мне поиграть с несколькими важными концепциями и практиками Data Science.

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

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

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

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

Код, который я использую, можно найти в моем репозитории GitHub:



Записную книжку Jupyter также можно посмотреть здесь.

Данные

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



Платформа содержит данные по 37 европейским странам, но в этом проекте я сосредоточусь на данных по Германии за 2016 год. В частности, я собираюсь использовать два набора данных:

  • Временные ряды с нагрузкой, ветром и солнцем, ценами в почасовом разрешении. CSV-файл с данными по всем 37 странам за 2006 и 2017 годы можно получить здесь.
  • Данные о погоде: скорость ветра, радиация, температура и другие данные. Учитывая огромный объем данных, платформа Open Power System Data предоставляет CSV-файл для немецкого набора данных за 2016 год (который можно найти здесь) и сценарий для загрузки данных за другие страны и годы.

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

Ветровая и солнечная генерация

Во-первых, мы начнем с файла CSV с временными рядами для 37 европейских стран за 2006 и 2017 годы, но читаем только данные по Германии:

production = pd.read_csv("data/time_series_60min_singleindex.csv",
                        usecols=(lambda s: s.startswith('utc') | 
                                 s.startswith('DE')),
                        parse_dates=[0], index_col=0)

Использование optionparse_dates=[0] вместе с index_col=0 гарантирует, что столбец с датой и временем каждого измерения будет сохранен как DatetimeIndex.

После фильтрации строк за 2016 год мы получаем DataFrame с 8784 записями (количество часов в високосном году, например 2016) и 48 столбцами, каждый из которых относится к разному количеству, например солнечной мощности, ветровой мощности и т. Д. (Вы полный список можно увидеть здесь). Меня заинтересуют только два из них:

  • «DE_solar_generation_actual» с фактической солнечной генерацией в МВт;
  • «DE_wind_generation_actual» с фактической ветровой выработкой в ​​МВт.

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

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

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

Данные о погоде

Теперь мы читаем CSV-файл с данными о погоде в Германии за 2016 год.

weather = pd.read_csv("data/weather_data_GER_2016.csv",
                     parse_dates=[0], index_col=0)

Если мы проверим информационный атрибут weather DataFrame, мы получим:

<class 'pandas.core.frame.DataFrame'>
DatetimeIndex: 2248704 entries, 2016-01-01 00:00:00 to 
2016-12-31 23:00:00
Data columns (total 14 columns):
cumulated hours    int64
lat                float64
lon                float64
v1                 float64
v2                 float64
v_50m              float64
h1                 int64
h2                 int64
z0                 float64
SWTDN              float64
SWGDN              float64
T                  float64
rho                float64
p                  float64
dtypes: float64(11), int64(3)
memory usage: 257.3 MB

Это 2248704 записи! Если вы посчитаете, это соответствует 8784 записям для 256 географических «фрагментов» Германии, каждая из которых характеризуется своей широтой lat и длинной строкой lon. Остальные столбцы выглядят следующим образом:

Параметры ветра:

  • v1: скорость [м / с] на высоте h1 (2 метра над высотой смещения);
  • v2: скорость [м / с] на высоте h2 (10 метров над высотой смещения);
  • v_50m: скорость [м / с] на высоте 50 метров над землей;
  • h1: высота над землей [м] (h1 = высота смещения + 2 м);
  • h2: высота над землей [м] (h2 = высота смещения + 10 м);
  • z0: длина шероховатости [м];

Параметры Солнца:

  • SWTDN: общее горизонтальное излучение над атмосферой [Вт / м²];
  • SWGDN: общее горизонтальное излучение земли [Вт / м²];

Данные о температуре:

  • T: Температура [K] на высоте 2 метра над высотой вытеснения (см. H1);

Данные по воздуху:

  • Rho: плотность воздуха [кг / м³] у поверхности;
  • p: давление воздуха [Па] у поверхности.

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

У нас есть некоторые ограничения для полного анализа, например, мы не знаем местонахождение ветряных турбин и солнечных батарей в Германии. Учитывая цели этого проекта, я просто сгруппирую данные о погоде по каждому часу и возьму среднее значение по географическим «чакам». Таким образом, мы получаем DataFrame с 8784 записями, которые мы позже можем объединить с первым DataFrame.

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

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

Горизонтальная радиация на уровне земли, как и ожидалось, была выше в летние месяцы, также как и температура, как показано на графике ниже.

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

Кажется, что существует линейная зависимость между генерацией ветра и скоростями ветра v1, v2 и v_50m, но не другими величинами.

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

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

Прогнозирование ветровой и солнечной генерации с помощью линейной регрессии

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

куда

- вектор параметров. Цель состоит в том, чтобы найти параметры, которые минимизируют среднеквадратичную ошибку:

Этого можно добиться с помощьюLinearRegression из библиотеки scikit-learn.

Генерация ветра

Для прогнозирования ветровой генерации мы строим матрицу характеристик X_wind с характеристиками v1, v2 и v_50m, а цель Y_wind - с фактической ветровой генерацией. Затем реализуем алгоритм:

from sklearn.linear_model import LinearRegression
from sklearn.model_selection import cross_val_score
lr = LinearRegression()
scores_wind = cross_val_score(lr, X_wind, y_wind, cv=5)
print(scores_wind, "\naverage =", np.mean(scores_wind))

Давайте проанализируем, что здесь происходит, если вы не знакомы с этим:

  • Мы импортируем LinearRegression из sklearn.linear_model, который реализует обычную линейную регрессию методом наименьших квадратов. (Более подробную информацию можно найти в документации.)
  • Чтобы оценить производительность алгоритма, мы разделяем данные с помощью процедуры под названием перекрестная проверка (сокращенно CV). Для k-кратной CV набор данных разбивается на k меньших наборов или "кратностей", модель обучается за k -1 из эти складки, и получившаяся модель проверяется на оставшейся части данных. Показатель производительности, предоставляемый CV, тогда является средним показателем производительности, вычисленным в каждом эксперименте. В приведенном выше коде мы используем cross_val_score из sklearn.model_selection с количеством складок cv=5 (подробнее в документации).

  • Показателем эффективности, который LinearRegression дает по умолчанию, является коэффициент детерминации R ² прогноза. Он измеряет, насколько хорошо прогнозы соответствуют истинным значениям. Значение, близкое к 1, означает, что регрессия делает прогнозы, близкие к истинным значениям. Формально рассчитывается по формуле:

Вывод кода выше для нашего случая:

[0.88261401 0.88886305 0.83623262 0.88974363 0.85338174] 
average = 0.870167010172279

Первая строка содержит пять значений R ² для каждого из 5 значений процедуры перекрестной проверки, а вторая строка - их среднее значение. Мы видим, что наша линейная модель имеет R ² приблизительно 0,87, что неплохо для такой простой модели! Мы можем сделать хорошие прогнозы относительно ветровой генерации в Германии в 2016 году, учитывая только скорость ветра на разных высотах.

Солнечная генерация

Чтобы предсказать солнечную генерацию, мы следуем очень похожей процедуре. Мы снова строим матрицу характеристик X_solar, но теперь с функциями SWTDN, SWGDN и T, а цель Y_solar с фактической солнечной генерацией. Затем реализуем алгоритм:

scores_solar = cross_val_score(lr, X_solar, y_solar, cv=5)
print(scores_solar, "\naverage =", np.mean(scores_solar))

Результат:

[0.8901974  0.95027431 0.95982151 0.95090201 0.8715077 ] 
average = 0.9245405855731855

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

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

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



Вы можете найти меня в LinkedIn: