Примечание
Перейти к концу для скачивания полного кода примера. или для запуска этого примера в вашем браузере через JupyterLite или Binder
Модели, основанные на L1, для разреженных сигналов
В данном примере сравниваются три модели регрессии на основе L1 на синтетическом сигнале, полученном из разреженных и коррелированных признаков, которые дополнительно искажены аддитивным гауссовским шумом:
- модель Lasso;
- модель Автоматического определения релевантности - ARD;
- модель Elastic-Net.
Известно, что оценки Lasso оказываются близки к оценкам модели выбора при увеличении размерности данных, при условии, что нерелевантные переменные не слишком коррелированы с релевантными. При наличии коррелированных признаков Lasso сам по себе не может выбрать правильный шаблон разреженности [1].
Здесь мы сравниваем производительность трех моделей по показателю \(R^2\), времени обучения и разреженности оцениваемых коэффициентов по сравнению с истинными значениями.
# Authors: The scikit-learn developers # SPDX-License-Identifier: BSD-3-Clause
Генерация синтетического набора данных
Мы генерируем набор данных, где количество выборок меньше общего числа признаков. Это приводит к недоопределенной системе, т. е. решение не является уникальным, и поэтому мы не можем применить обычный метод наименьших квадратов сам по себе. Регуляризация добавляет член штрафа к целевой функции, что изменяет задачу оптимизации и может помочь смягчить недоопределенность системы.
Целевой y является линейной комбинацией синусоидальных сигналов с чередующимися знаками. Использованы только 10 наименьших из 100 частот в X для генерации y, в то время как остальные признаки не информативны. Это приводит к высокоразмерному разреженному пространству признаков, где необходима какая-то степень L1-регуляризации.
import numpy as np
rng = np.random.RandomState(0)
n_samples, n_features, n_informative = 50, 100, 10
time_step = np.linspace(-2, 2, n_samples)
freqs = 2 * np.pi * np.sort(rng.rand(n_features)) / 0.01
X = np.zeros((n_samples, n_features))
for i in range(n_features):
X[:, i] = np.sin(freqs[i] * time_step)
idx = np.arange(n_features)
true_coef = (-1) ** idx * np.exp(-idx / 10)
true_coef[n_informative:] = 0 # sparsify coef
y = np.dot(X, true_coef)
Некоторые из информативных признаков имеют близкие частоты, чтобы вызвать (анти-)корреляции.
freqs[:n_informative]
array([ 2.9502547 , 11.8059798 , 12.63394388, 12.70359377, 24.62241605,
37.84077985, 40.30506066, 44.63327171, 54.74495357, 59.02456369])
Случайная фаза вводится с помощью numpy.random.random_sample, а некоторый гауссовский шум (реализованный с помощью numpy.random.normal) добавляется как к признакам, так и к целевой переменной.
for i in range(n_features):
X[:, i] = np.sin(freqs[i] * time_step + 2 * (rng.random_sample() - 0.5))
X[:, i] += 0.2 * rng.normal(0, 1, n_samples)
y += 0.2 * rng.normal(0, 1, n_samples)
Такие разреженные, шумные и коррелированные признаки могут быть получены, например, от сенсорных узлов, контролирующих некоторые переменные окружающей среды, поскольку они обычно регистрируют похожие значения в зависимости от их расположения (пространственная корреляция). Мы можем визуализировать целевую переменную.
import matplotlib.pyplot as plt
plt.plot(time_step, y)
plt.ylabel("target signal")
plt.xlabel("time")
_ = plt.title("Superposition of sinusoidal signals")

Для простоты данные разбиваются на обучающую и тестовую выборки. На практике следует использовать TimeSeriesSplit кросс-валидацию для оценки дисперсии тестовой метрики. Здесь мы установили shuffle="False", так как при работе с данными, имеющими временную зависимость, нельзя использовать обучающие данные, которые следуют за тестовыми данными.
from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.5, shuffle=False)
В дальнейшем мы вычислим производительность трех моделей на основе L1 по показателю качества подгонки \(R^2\) и времени обучения. Затем мы построим график для сравнения разреженности оцениваемых коэффициентов с истинными коэффициентами и, наконец, проанализируем полученные результаты.
Lasso
В этом примере мы демонстрируем Lasso с фиксированным значением параметра регуляризации alpha. На практике оптимальный параметр alpha следует выбирать, передавая TimeSeriesSplit стратегию кросс-валидации в LassoCV. Чтобы сохранить пример простым и быстрым в выполнении, мы здесь непосредственно задаем оптимальное значение для alpha.
from time import time
from sklearn.linear_model import Lasso
from sklearn.metrics import r2_score
t0 = time()
lasso = Lasso(alpha=0.14).fit(X_train, y_train)
print(f"Lasso fit done in {(time() - t0):.3f}s")
y_pred_lasso = lasso.predict(X_test)
r2_score_lasso = r2_score(y_test, y_pred_lasso)
print(f"Lasso r^2 on test data : {r2_score_lasso:.3f}")
Lasso fit done in 0.001s Lasso r^2 on test data : 0.480
Автоматическое определение релевантности (ARD)
Регрессия ARD является байесовской версией Lasso. Она может давать интервальные оценки для всех параметров, включая дисперсию ошибки, если это необходимо. Это подходящий вариант, когда сигналы имеют гауссовский шум. См. пример Сравнение линейных байесовских регрессоров для сравнения ARDRegression и BayesianRidge регрессоров.
from sklearn.linear_model import ARDRegression
t0 = time()
ard = ARDRegression().fit(X_train, y_train)
print(f"ARD fit done in {(time() - t0):.3f}s")
y_pred_ard = ard.predict(X_test)
r2_score_ard = r2_score(y_test, y_pred_ard)
print(f"ARD r^2 on test data : {r2_score_ard:.3f}")
ARD fit done in 0.019s ARD r^2 on test data : 0.543
ElasticNet
ElasticNet является промежуточным вариантом между Lasso и Ridge, так как объединяет L1 и L2-штрафы. Величина регуляризации контролируется двумя гиперпараметрами l1_ratio и alpha. Для l1_ratio =
0 штраф представляет собой чистую L2-регуляризацию, и модель эквивалентна Ridge. Аналогично, l1_ratio = 1 представляет собой чистый L1-штраф, и модель эквивалентна Lasso. Для 0 < l1_ratio < 1 штраф представляет собой комбинацию L1 и L2.
Как и прежде, мы обучаем модель с фиксированными значениями alpha и l1_ratio. Для выбора их оптимальных значений мы использовали ElasticNetCV, что не показано здесь для простоты примера.
from sklearn.linear_model import ElasticNet
t0 = time()
enet = ElasticNet(alpha=0.08, l1_ratio=0.5).fit(X_train, y_train)
print(f"ElasticNet fit done in {(time() - t0):.3f}s")
y_pred_enet = enet.predict(X_test)
r2_score_enet = r2_score(y_test, y_pred_enet)
print(f"ElasticNet r^2 on test data : {r2_score_enet:.3f}")
ElasticNet fit done in 0.001s ElasticNet r^2 on test data : 0.636
График и анализ результатов
В этом разделе мы используем тепловую карту для визуализации разреженности истинных и оцениваемых коэффициентов соответствующих линейных моделей.
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns
from matplotlib.colors import SymLogNorm
df = pd.DataFrame(
{
"True coefficients": true_coef,
"Lasso": lasso.coef_,
"ARDRegression": ard.coef_,
"ElasticNet": enet.coef_,
}
)
plt.figure(figsize=(10, 6))
ax = sns.heatmap(
df.T,
norm=SymLogNorm(linthresh=10e-4, vmin=-1, vmax=1),
cbar_kws={"label": "coefficients' values"},
cmap="seismic_r",
)
plt.ylabel("linear model")
plt.xlabel("coefficients")
plt.title(
f"Models' coefficients\nLasso $R^2$: {r2_score_lasso:.3f}, "
f"ARD $R^2$: {r2_score_ard:.3f}, "
f"ElasticNet $R^2$: {r2_score_enet:.3f}"
)
plt.tight_layout()

В данном примере ElasticNet дает лучший результат и захватывает большинство предсказательных признаков, но все еще не находит все истинные компоненты. Обратите внимание, что как ElasticNet, так и ARDRegression приводят к менее разреженной модели, чем Lasso.
Выводы
Lasso известен тем, что эффективно восстанавливает разреженные данные, но плохо работает с сильно коррелированными признаками. Действительно, если несколько коррелированных признаков вносят вклад в целевую переменную, Lasso в итоге выберет только один из них. В случае разреженных, но некоррелированных признаков, модель Lasso будет более подходящей.
ElasticNet вносит некоторую разреженность в коэффициенты и сжимает их значения к нулю. Таким образом, при наличии коррелированных признаков, которые вносят вклад в целевую переменную, модель по-прежнему способна уменьшить их веса, не устанавливая их точно в ноль. Это приводит к менее разреженной модели, чем чисто Lasso, и может захватить также и непредсказательные признаки.
ARDRegression лучше справляется с гауссовским шумом, но по-прежнему не может обрабатывать коррелированные признаки и требует большего времени из-за подгонки априорного распределения.
Ссылки
Общее время выполнения скрипта: (0 минут 0.517 секунд)
Связанные примеры
© 2007–2025 The scikit-learn developers
Licensed under the 3-clause BSD License.
https://scikit-learn.org/1.6/auto_examples/linear_model/plot_lasso_and_elasticnet.html