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

Это вторая часть серии Временные ряды изменений климата. Список статей:

Солнечные энергетические системы

Солнечная энергия становится все более распространенным источником чистой энергии.

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

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

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

Помимо производства энергии

Прогнозирование солнечной радиации имеет и другие применения помимо энергетики, например:

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

Проблемы и что дальше

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

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

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

Учебное пособие. Прогнозирование солнечной радиации

Этот учебник основан на наборе данных, собранном Министерством сельского хозяйства США. Вы можете проверить более подробную информацию в ссылке [1]. Полный код этого руководства доступен на Github:

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

  • Солнечная радиация (ватт на квадратный метр);
  • Направление ветра;
  • глубина снега;
  • Скорость ветра;
  • температура точки росы;
  • Атмосферные осадки;
  • Давление газа;
  • Относительная влажность;
  • Температура воздуха.

Ряд охватывает период с 1 октября 2007 г. по 1 октября 2013 г. Он собирается с почасовой частотой, всего 52 608 наблюдений.

После загрузки данных мы можем прочитать их с помощью pandas:

import re
import pandas as pd
# src module available here: https://github.com/vcerqueira/tsa4climate/tree/main/src
from src.log import LogTransformation

# a sample here: https://github.com/vcerqueira/tsa4climate/tree/main/content/part_2/assets
assets = 'path_to_data_directory'

DATE_TIME_COLS = ['month', 'day', 'calendar_year', 'hour']
# we'll focus on the data collected at particular station called smf1
STATION = 'smf1'

COLUMNS_PER_FILE = \
    {'incoming_solar_final.csv': DATE_TIME_COLS + [f'{STATION}_sin_w/m2'],
     'wind_dir_raw.csv': DATE_TIME_COLS + [f'{STATION}_wd_deg'],
     'snow_depth_final.csv': DATE_TIME_COLS + [f'{STATION}_sd_mm'],
     'wind_speed_final.csv': DATE_TIME_COLS + [f'{STATION}_ws_m/s'],
     'dewpoint_final.csv': DATE_TIME_COLS + [f'{STATION}_dpt_C'],
     'precipitation_final.csv': DATE_TIME_COLS + [f'{STATION}_ppt_mm'],
     'vapor_pressure.csv': DATE_TIME_COLS + [f'{STATION}_vp_Pa'],
     'relative_humidity_final.csv': DATE_TIME_COLS + [f'{STATION}_rh'],
     'air_temp_final.csv': DATE_TIME_COLS + [f'{STATION}_ta_C'],
     }

data_series = {}
for file in COLUMNS_PER_FILE:
    file_data = pd.read_csv(f'{assets}/{file}')

    var_df = file_data[COLUMNS_PER_FILE[file]]

    var_df['datetime'] = \
        pd.to_datetime([f'{year}/{month}/{day} {hour}:00'
                        for year, month, day, hour in zip(var_df['calendar_year'],
                                                          var_df['month'],
                                                          var_df['day'],
                                                          var_df['hour'])])

    var_df = var_df.drop(DATE_TIME_COLS, axis=1)
    var_df = var_df.set_index('datetime')
    series = var_df.iloc[:, 0].sort_index()

    data_series[file] = series

mv_series = pd.concat(data_series, axis=1)
mv_series.columns = [re.sub('_final.csv|_raw.csv|.csv', '', x) for x in mv_series.columns]
mv_series.columns = [re.sub('_', ' ', x) for x in mv_series.columns]
mv_series.columns = [x.title() for x in mv_series.columns]

mv_series = mv_series.astype(float)

Этот код приводит к следующему набору данных:

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

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

Мы также можем визуализировать переменную солнечного излучения по отдельности:

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

Мы также можем проанализировать корреляцию между каждой парой переменных:

Солнечное излучение коррелирует с некоторыми переменными. Например, температура воздуха, относительная влажность (отрицательная корреляция) или скорость ветра.

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

Как мы можем сделать это?

Учебник по моделированию авторегрессивных распределенных задержек

Авторегрессионные распределенные лаги (ARDL) — это метод моделирования многомерных временных рядов.

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

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

Преобразование данных для ARDL

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

import pandas as pd

def mts_to_tabular(data: pd.DataFrame,
                   n_lags: int,
                   horizon: int,
                   return_Xy: bool = False,
                   drop_na: bool = True):
    """
    Time delay embedding with multivariate time series
    Time series for supervised learning

    :param data: multivariate time series as pd.DataFrame
    :param n_lags: number of past values to used as explanatory variables
    :param horizon: how many values to forecast
    :param return_Xy: whether to return the lags split from future observations

    :return: pd.DataFrame with reconstructed time series
    """

    # applying time delay embedding to each variable
    data_list = [time_delay_embedding(data[col], n_lags, horizon)
                 for col in data]
    
    # concatenating the results in a single dataframe
    df = pd.concat(data_list, axis=1)

    if drop_na:
        df = df.dropna()

    if not return_Xy:
        return df

    is_future = df.columns.str.contains('\+')

    X = df.iloc[:, ~is_future]
    Y = df.iloc[:, is_future]

    if Y.shape[1] == 1:
        Y = Y.iloc[:, 0]

    return X, Y

Эта функция применяется к данным следующим образом:

from sklearn.model_selection import train_test_split

# target variable
TARGET = 'Solar Irradiance'
# number of lags for each variable
N_LAGS = 24
# forecasting horizon for solar irradiance
HORIZON = 48

# leaving the last 30% of observations for testing
train, test = train_test_split(mv_series, test_size=0.3, shuffle=False)

# transforming the time series into a tabular format
X_train, Y_train_all = mts_to_tabular(train, N_LAGS, HORIZON, return_Xy=True)
X_test, Y_test_all = mts_to_tabular(train, N_LAGS, HORIZON, return_Xy=True)

# subsetting the target variable
target_columns = Y_train_all.columns.str.contains(TARGET)
Y_train = Y_train_all.iloc[:, target_columns]
Y_test = Y_test_all.iloc[:, target_columns]

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

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

Построение модели прогнозирования

Перед построением модели мы извлекаем еще 8 признаков на основе даты и времени. К ним относятся такие данные, как день в году или час, которые полезны для моделирования сезонности.

Мы уменьшаем количество объясняющих переменных с помощью выбора признаков. Во-первых, мы применяем корреляционный фильтр. Это используется для удаления любой функции с корреляцией более 95% с любой другой независимой переменной. Затем мы также применяем рекурсивное исключение признаков (RFE) на основе оценок важности случайного леса. После разработки признаков мы обучаем модель с помощью случайного леса.

Мы используем Pipeline и RandomSearchCV от sklearn для оптимизации параметров различных шагов:

from sklearn.pipeline import Pipeline
from sklearn.preprocessing import FunctionTransformer
from sklearn.feature_selection import RFE
from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import RandomizedSearchCV
from sktime.transformations.series.date import DateTimeFeatures

from src.holdout import Holdout

# including datetime information to model seasonality
hourly_feats = DateTimeFeatures(ts_freq='H',
                                keep_original_columns=True,
                                feature_scope='efficient')

# building a pipeline
pipeline = Pipeline([
    # feature extraction based on datetime
    ('extraction', hourly_feats),
    # removing correlated explanatory variables
    ('correlation_filter', FunctionTransformer(func=correlation_filter)),
    # applying feature selection based on recursive feature elimination
    ('select', RFE(estimator=RandomForestRegressor(max_depth=5), step=3)),
    # building a random forest model for forecasting
    ('model', RandomForestRegressor())]
)

# parameter grid for optimization
param_grid = {
    'extraction': ['passthrough', hourly_feats],
    'select__n_features_to_select': np.linspace(start=.1, stop=1, num=10),
    'model__n_estimators': [100, 200]
}

# optimizing the pipeline with random search
model = RandomizedSearchCV(estimator=pipeline,
                           param_distributions=param_grid,
                           scoring='neg_mean_squared_error',
                           n_iter=25,
                           n_jobs=5,
                           refit=True,
                           verbose=2,
                           cv=Holdout(n=X_train.shape[0]),
                           random_state=123)

# running random search
model.fit(X_train, Y_train)

# checking the selected model
model.best_estimator_
# Pipeline(steps=[('extraction',
#                  DateTimeFeatures(feature_scope='efficient', ts_freq='H')),
#                 ('correlation_filter',
#                  FunctionTransformer(func=<function correlation_filter at 0x28cccfb50>)),
#                 ('select',
#                  RFE(estimator=RandomForestRegressor(max_depth=5),
#                      n_features_to_select=0.9, step=3)),
#                 ('model', RandomForestRegressor(n_estimators=200))])

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

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

# getting forecasts for the test set
forecasts = model.predict(X_test)
forecasts = pd.DataFrame(forecasts, columns=Y_test.columns)

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

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

Ключевые выводы

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

Спасибо за прочтение и до встречи в следующей истории!

Рекомендации

[1] Данные о погоде, снеге и речном стоке из четырех экспериментальных водосборных бассейнов с преобладанием можжевельника на юго-западе штата Айдахо, США. (Лицензия: общественное достояние США)

[2] Ролник, Дэвид и др. «Борьба с изменением климата с помощью машинного обучения». Вычислительные исследования ACM (CSUR) 55.2 (2022): 1–96.