L1 기반 모델을 이용한 희소 신호 회귀

Beginner

This tutorial is from open-source community. Access the source code

소개

이 실험에서는 고차원 및 희소 신호를 처리하기 위해 L1 기반 회귀 모델을 사용하는 방법을 보여줍니다. 특히, Lasso, Automatic Relevance Determination (ARD) 및 ElasticNet 이라는 세 가지 인기 있는 L1 기반 모델을 비교합니다. 합성 데이터셋을 사용하여 이러한 모델의 적합 시간, R2 점수 및 추정 계수의 희소성 측면에서 성능을 보여줍니다.

VM 팁

VM 시작이 완료되면 왼쪽 상단 모서리를 클릭하여 Notebook 탭으로 전환하여 연습을 위한 Jupyter Notebook에 접근합니다.

때때로 Jupyter Notebook 이 완전히 로드되기까지 몇 초 정도 기다려야 할 수 있습니다. Jupyter Notebook 의 제한으로 인해 작업의 유효성 검사를 자동화할 수 없습니다.

학습 중 문제가 발생하면 Labby 에 문의하십시오. 세션 후 피드백을 제공하면 문제를 신속하게 해결해 드리겠습니다.

합성 데이터셋 생성

먼저, 샘플 수가 전체 특징 수보다 적은 데이터셋을 생성합니다. 이는 과소결정 시스템 (즉, 해결책이 유일하지 않고, 일반적인 최소 제곱법 자체를 적용할 수 없음) 을 초래합니다. 정규화는 목적 함수에 페널티 항을 도입하여 최적화 문제를 수정하고 시스템의 과소결정 특성을 완화하는 데 도움이 될 수 있습니다. 우리는 사인파 신호의 교대로 부호가 바뀌는 선형 결합인 대상 y를 생성할 것입니다. X의 100 개 주파수 중에서 가장 낮은 10 개만 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)

## introduce random phase using numpy.random.random_sample
## add some gaussian noise using 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)

## split the data into train and test sets using train_test_split from sklearn
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)

Lasso

이 단계에서는 Lasso 회귀 모델을 사용하여 데이터셋의 희소 계수를 추정하는 방법을 보여줍니다. 정규화 매개변수 alpha의 고정 값을 사용합니다. 실제로는 최적의 매개변수 alphaLassoCVTimeSeriesSplit 교차 검증 전략을 전달하여 선택해야 합니다. 예시를 간단하고 빠르게 실행하기 위해 여기서는 alpha 의 최적 값을 직접 설정합니다.

from sklearn.linear_model import Lasso
from sklearn.metrics import r2_score
from time import time

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}")

자동 관련성 결정 (ARD)

ARD 회귀는 Lasso 의 베이지안 버전입니다. 필요한 경우 오차 분산을 포함한 모든 매개변수에 대한 구간 추정값을 생성할 수 있습니다. 신호에 가우시안 잡음이 있는 경우 적절한 옵션입니다.

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}")

ElasticNet

ElasticNet 은 Lasso 와 Ridge 회귀 사이의 중간 지점으로 L1 및 L2 페널티를 결합합니다. 정규화의 양은 두 하이퍼파라미터 l1_ratioalpha로 제어됩니다. l1_ratio = 0인 경우 페널티는 순수한 L2 이며 모델은 Ridge 회귀와 동일합니다. 마찬가지로 l1_ratio = 1은 순수한 L1 페널티이며 모델은 Lasso 회귀와 동일합니다. 0 < l1_ratio < 1인 경우 페널티는 L1 과 L2 의 조합입니다.

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}")

결과 플롯 및 분석

이 단계에서는 히트맵을 사용하여 각 선형 모델의 실제 및 추정 계수의 희소성을 시각화합니다.

import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
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": "계수 값"},
    cmap="seismic_r",
)
plt.ylabel("선형 모델")
plt.xlabel("계수")
plt.title(
    f"모델 계수\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()

요약

Lasso 는 희소 데이터를 효과적으로 복구하는 것으로 알려져 있지만, 높은 상관 관계를 가진 특징들에 대해서는 성능이 좋지 않습니다. 실제로, 여러 개의 상관된 특징들이 목표에 기여하는 경우, Lasso 는 그 중 하나만 선택하게 됩니다. 희소하지만 상관 관계가 없는 특징의 경우, Lasso 모델이 더 적합합니다.

ElasticNet 은 계수에 약간의 희소성을 도입하고 그 값을 0 으로 줄입니다. 따라서, 목표에 기여하는 상관된 특징들이 있는 경우, 모델은 정확히 0 으로 설정하지 않고도 그들의 가중치를 줄일 수 있습니다. 이는 순수한 Lasso 보다 희소성이 덜한 모델을 생성하며, 예측력이 없는 특징도 포착할 수 있습니다.

ARDRegression 은 가우시안 노이즈를 처리할 때 더 나은 성능을 보이지만, 여전히 상관된 특징을 처리할 수 없으며, 사전을 맞추는 데 더 많은 시간이 필요합니다.