Spec-Zone.ru › scikit-learn

Примечание

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

Прогнозирование уровня CO2 по набору данных Mona Loa с помощью регрессии Гауссова процесса (GPR)

Этот пример основан на разделе 5.4.3 «Гауссовы процессы для машинного обучения» [1]. Он демонстрирует пример сложного проектирования ядра и оптимизации гиперпараметров с использованием градиентного восхождения по логарифмическому маргинальному правдоподобию. Данные состоят из ежемесячных средних концентраций атмосферного CO2 (в частях на миллион по объему (ppm)), собранных в обсерватории Мауна-Лоа на Гавайях, в период с 1958 по 2001 год. Цель состоит в том, чтобы смоделировать концентрацию CO2 как функцию времени \(t\) и экстраполировать на годы после 2001 года.

Ссылки

[1]

Rasmussen, Carl Edward. “Gaussian processes in machine learning.” Summer school on machine learning. Springer, Berlin, Heidelberg, 2003.

print(__doc__)

# Authors: The scikit-learn developers
# SPDX-License-Identifier: BSD-3-Clause

Создание набора данных

Мы получим набор данных из обсерватории Мауна-Лоа, которая собирала образцы воздуха. Мы заинтересованы в оценке концентрации CO2 и экстраполяции ее на будущие годы. Сначала мы загружаем исходный набор данных, доступный в OpenML, в виде pandas DataFrame. Это будет заменено Polars, как только fetch_openml добавит в него родную поддержку.

from sklearn.datasets import fetch_openml

co2 = fetch_openml(data_id=41187, as_frame=True)
co2.frame.head()
year month day weight flag station co2
0 1958 3 29 4 0 MLO 316.1
1 1958 4 5 6 0 MLO 317.3
2 1958 4 12 4 0 MLO 317.6
3 1958 4 19 6 0 MLO 317.5
4 1958 4 26 2 0 MLO 316.4


Сначала мы обрабатываем исходный DataFrame, чтобы создать столбец даты и выбрать его вместе со столбцом CO2.

import polars as pl

co2_data = pl.DataFrame(co2.frame[["year", "month", "day", "co2"]]).select(
    pl.date("year", "month", "day"), "co2"
)
co2_data.head()
формат: (5, 2)
date co2
date f64
1958-03-29 316.1
1958-04-05 317.3
1958-04-12 317.6
1958-04-19 317.5
1958-04-26 316.4


co2_data["date"].min(), co2_data["date"].max()
(datetime.date(1958, 3, 29), datetime.date(2001, 12, 29))

Мы видим, что получаем концентрацию CO2 в некоторые дни с марта 1958 года по декабрь 2001 года. Мы можем построить эту исходную информацию, чтобы лучше понять ее.

import matplotlib.pyplot as plt

plt.plot(co2_data["date"], co2_data["co2"])
plt.xlabel("date")
plt.ylabel("CO$_2$ concentration (ppm)")
_ = plt.title("Raw air samples measurements from the Mauna Loa Observatory")
Raw air samples measurements from the Mauna Loa Observatory

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

co2_data = (
    co2_data.sort(by="date")
    .group_by_dynamic("date", every="1mo")
    .agg(pl.col("co2").mean())
    .drop_nulls()
)
plt.plot(co2_data["date"], co2_data["co2"])
plt.xlabel("date")
plt.ylabel("Monthly average of CO$_2$ concentration (ppm)")
_ = plt.title(
    "Monthly average of air samples measurements\nfrom the Mauna Loa Observatory"
)
Monthly average of air samples measurements from the Mauna Loa Observatory

В этом примере идея заключается в прогнозировании концентрации CO2 в зависимости от даты. Мы также заинтересованы в экстраполяции на последующие годы после 2001 года.

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

X = co2_data.select(
    pl.col("date").dt.year() + pl.col("date").dt.month() / 12
).to_numpy()
y = co2_data["co2"].to_numpy()

Проектирование подходящего ядра

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

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

from sklearn.gaussian_process.kernels import RBF

long_term_trend_kernel = 50.0**2 * RBF(length_scale=50.0)

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

from sklearn.gaussian_process.kernels import ExpSineSquared

seasonal_kernel = (
    2.0**2
    * RBF(length_scale=100.0)
    * ExpSineSquared(length_scale=1.0, periodicity=1.0, periodicity_bounds="fixed")
)

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

from sklearn.gaussian_process.kernels import RationalQuadratic

irregularities_kernel = 0.5**2 * RationalQuadratic(length_scale=1.0, alpha=1.0)

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

from sklearn.gaussian_process.kernels import WhiteKernel

noise_kernel = 0.1**2 * RBF(length_scale=0.1) + WhiteKernel(
    noise_level=0.1**2, noise_level_bounds=(1e-5, 1e5)
)

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

co2_kernel = (
    long_term_trend_kernel + seasonal_kernel + irregularities_kernel + noise_kernel
)
co2_kernel
50**2 * RBF(length_scale=50) + 2**2 * RBF(length_scale=100) * ExpSineSquared(length_scale=1, periodicity=1) + 0.5**2 * RationalQuadratic(alpha=1, length_scale=1) + 0.1**2 * RBF(length_scale=0.1) + WhiteKernel(noise_level=0.01)

Подгонка модели и экстраполяция

Теперь мы готовы использовать регрессор гауссова процесса и подогнать имеющиеся данные. Чтобы следовать примеру из литературы, мы вычтем среднее значение из целевой переменной. Мы могли бы использовать normalize_y=True. Однако в этом случае мы также масштабировали бы целевую переменную (разделив y на ее стандартное отклонение). Таким образом, гиперпараметры различных ядер имели бы разное значение, поскольку они не были бы выражены в ppm.

from sklearn.gaussian_process import GaussianProcessRegressor

y_mean = y.mean()
gaussian_process = GaussianProcessRegressor(kernel=co2_kernel, normalize_y=False)
gaussian_process.fit(X, y - y_mean)
GaussianProcessRegressor(kernel=50**2 * RBF(length_scale=50) + 2**2 * RBF(length_scale=100) * ExpSineSquared(length_scale=1, periodicity=1) + 0.5**2 * RationalQuadratic(alpha=1, length_scale=1) + 0.1**2 * RBF(length_scale=0.1) + WhiteKernel(noise_level=0.01))
В среде Jupyter, пожалуйста, перезапустите эту ячейку, чтобы отобразить HTML-представление, или доверьтесь блокноту.
На GitHub HTML-представление не может быть отображено, пожалуйста, попробуйте загрузить эту страницу с nbviewer.org.
GaussianProcessRegressor(kernel=50**2 * RBF(length_scale=50) + 2**2 * RBF(length_scale=100) * ExpSineSquared(length_scale=1, periodicity=1) + 0.5**2 * RationalQuadratic(alpha=1, length_scale=1) + 0.1**2 * RBF(length_scale=0.1) + WhiteKernel(noise_level=0.01))


Теперь мы воспользуемся гауссовым процессом для прогнозирования:

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

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

import datetime

import numpy as np

today = datetime.datetime.now()
current_month = today.year + today.month / 12
X_test = np.linspace(start=1958, stop=current_month, num=1_000).reshape(-1, 1)
mean_y_pred, std_y_pred = gaussian_process.predict(X_test, return_std=True)
mean_y_pred += y_mean
plt.plot(X, y, color="black", linestyle="dashed", label="Measurements")
plt.plot(X_test, mean_y_pred, color="tab:blue", alpha=0.4, label="Gaussian process")
plt.fill_between(
    X_test.ravel(),
    mean_y_pred - std_y_pred,
    mean_y_pred + std_y_pred,
    color="tab:blue",
    alpha=0.2,
)
plt.legend()
plt.xlabel("Year")
plt.ylabel("Monthly average of CO$_2$ concentration (ppm)")
_ = plt.title(
    "Monthly average of air samples measurements\nfrom the Mauna Loa Observatory"
)
Monthly average of air samples measurements from the Mauna Loa Observatory

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

Интерпретация гиперпараметров ядра

Теперь мы можем взглянуть на гиперпараметры ядра.

gaussian_process.kernel_
44.8**2 * RBF(length_scale=51.6) + 2.64**2 * RBF(length_scale=91.5) * ExpSineSquared(length_scale=1.48, periodicity=1) + 0.536**2 * RationalQuadratic(alpha=2.89, length_scale=0.968) + 0.188**2 * RBF(length_scale=0.122) + WhiteKernel(noise_level=0.0367)

Таким образом, большая часть целевого сигнала, с вычтенной средней величиной, объясняется долгосрочной восходящей тенденцией на ~45 ppm и длиной масштаба ~52 года. Периодический компонент имеет амплитуду ~2,6 ppm, время затухания ~90 лет и длину масштаба ~1,5. Большое время затухания указывает на то, что у нас есть компонент, очень близкий к сезонной периодичности. Коррелированный шум имеет амплитуду ~0,2 ppm с длиной масштаба ~0,12 года и вклад белого шума ~0,04 ppm. Таким образом, общий уровень шума очень невелик, что указывает на то, что данные могут быть очень хорошо объяснены моделью.

Общее время выполнения скрипта: (0 минут 4,187 секунды)

Launch binder
Launch JupyterLite

Download Jupyter notebook: plot_gpr_co2.ipynb

Download Python source code: plot_gpr_co2.py

Download zipped: plot_gpr_co2.zip

Связанные примеры

Регрессия с помощью Гауссовских процессов: базовый вводный пример

Возможность регрессии с помощью гауссовских процессов (GPR) оценивать уровень шума в данных

Сравнение регрессии с ядром и регрессии с гауссовским процессом

Классификация с помощью гауссовских процессов (GPC) на наборе данных iris

© 2007–2025 The scikit-learn developers
Licensed under the 3-clause BSD License.
https://scikit-learn.org/1.6/auto_examples/gaussian_process/plot_gpr_co2.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API