ริจ & แลสโซ

Basic

การถดถอยแบบริจและแลสโซ | ใช้การทำให้เป็นระเบียบเพื่อควบคุมการเรียนรู้เกิน

Created: Last updated: Read time: 2 min
まとめ
  • การถดถอยแบบริจเพิ่มโทษ L2 เพื่อลดความผันผวนของสัมประสิทธิ์ ทำให้เสถียรกว่าการถดถอยธรรมดาแม้ฟีเจอร์มีความสัมพันธ์สูง
  • การถดถอยแบบแลสโซเพิ่มโทษ L1 จึงบีบสัมประสิทธิ์บางตัวให้เป็นศูนย์ ส่งผลดีต่อการเลือกฟีเจอร์และการตีความโมเดล
  • การเลือกความแรงของการทำให้เป็นระเบียบ \(\alpha\) ช่วยสร้างสมดุลระหว่างการฟิตข้อมูลฝึกกับความสามารถในการทั่วไป
  • เมื่อรวมการทำมาตรฐานและการตรวจสอบไขว้ จะเลือกพารามิเตอร์ได้มั่นใจและลดการเรียนรู้เกินได้ง่าย

ภาพรวมเชิงสัญชาติญาณ #

วิธีกำลังสองน้อยที่สุดไวต่อ outlier และความสัมพันธ์ระหว่างฟีเจอร์ ทำให้สัมประสิทธิ์อาจใหญ่เกินจริง ริจและแลสโซจึงเพิ่มโทษกับสัมประสิทธิ์เพื่อป้องกันไม่ให้ค่าบานปลาย ริจทำให้สัมประสิทธิ์ “หดอย่างนุ่มนวล” ส่วนแลสโซ “ตัด” ค่าที่ไม่จำเป็นให้เป็นศูนย์

สูตรสำคัญ #

ฟังก์ชันวัตถุประสงค์ของทั้งสองวิธีคือการบวกโทษลงในความคลาดเคลื่อนกำลังสอง

  • Ridge $$ \min_{\boldsymbol\beta, b} \sum_{i=1}^{n} \left(y_i - (\boldsymbol\beta^\top \mathbf{x}_i + b)\right)^2 + \alpha \lVert \boldsymbol\beta \rVert_2^2 $$

  • Lasso $$ \min_{\boldsymbol\beta, b} \sum_{i=1}^{n} \left(y_i - (\boldsymbol\beta^\top \mathbf{x}_i + b)\right)^2 + \alpha \lVert \boldsymbol\beta \rVert_1 $$

ค่า \(\alpha\) ยิ่งใหญ่ยิ่งบังคับให้สัมประสิทธิ์เล็กลง สำหรับแลสโซ เมื่อ \(\alpha\) เกินค่าหนึ่งสัมประสิทธิ์บางตัวจะเป็นศูนย์ ทำให้ได้โมเดลแบบสปาร์ส

ทดลองด้วย Python #

ตัวอย่างต่อไปนี้สร้างข้อมูลที่มีเพียงบางฟีเจอร์ที่มีผล แล้วเปรียบเทียบเส้นตรงทั่วไปกับ Ridge และ Lasso

import numpy as np
import matplotlib.pyplot as plt
import japanize_matplotlib
from sklearn.linear_model import Lasso, LassoCV, LinearRegression, Ridge, RidgeCV
from sklearn.model_selection import cross_val_score
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler

# พารามิเตอร์
n_samples = 200
n_features = 10
n_informative = 3
rng = np.random.default_rng(42)

# สร้างค่าน้ำหนักจริงแบบสปาร์ส
coef = np.zeros(n_features)
coef[:n_informative] = rng.normal(loc=3.0, scale=1.0, size=n_informative)

# สร้างฟีเจอร์และเป้าหมาย
X = rng.normal(size=(n_samples, n_features))
y = X @ coef + rng.normal(scale=5.0, size=n_samples)

# ฝึกโมเดล (ใช้ with_mean=False ตามตัวอย่างเดิม)
linear = make_pipeline(
    StandardScaler(with_mean=False),
    LinearRegression()
).fit(X, y)

ridge = make_pipeline(
    StandardScaler(with_mean=False),
    RidgeCV(alphas=np.logspace(-3, 3, 13), cv=5)
).fit(X, y)

lasso = make_pipeline(
    StandardScaler(with_mean=False),
    LassoCV(alphas=np.logspace(-3, 1, 9), cv=5, max_iter=50_000)
).fit(X, y)

models = {
    "Linear": linear,
    "Ridge": ridge,
    "Lasso": lasso,
}

# เปรียบเทียบค่าสัมประสิทธิ์
indices = np.arange(n_features)
width = 0.25
plt.figure(figsize=(10, 4))
plt.bar(indices - width, np.abs(linear[-1].coef_), width=width, label="Linear")
plt.bar(indices,         np.abs(ridge[-1].coef_),  width=width, label="Ridge")
plt.bar(indices + width, np.abs(lasso[-1].coef_),  width=width, label="Lasso")
plt.xlabel("ดัชนีฟีเจอร์")
plt.ylabel("|coefficient|")
plt.legend()
plt.grid(alpha=0.3)
plt.tight_layout()
plt.show()

# ความสามารถในการทั่วไป
for name, model in models.items():
    scores = cross_val_score(model, X, y, cv=5, scoring="r2")
    print(f"{name:>6}: R^2 = {scores.mean():.3f} ± {scores.std():.3f}")

วิเคราะห์ผลลัพธ์ #

  • Ridge ทำให้สัมประสิทธิ์ทุกตัวหดลงอย่างนุ่มนวล จึงยังคงใช้ฟีเจอร์ทั้งหมดแต่เสถียรขึ้น
  • Lasso ทำให้บางสัมประสิทธิ์เป็นศูนย์ ส่งผลให้เหลือเฉพาะฟีเจอร์ที่จำเป็น
  • เลือกค่า \(\alpha\) ด้วย cross-validation จะช่วยคุมความสมดุลระหว่างการฟิตชุดฝึกกับการทั่วไป

เอกสารอ้างอิง #

  • Hoerl, A. E., & Kennard, R. W. (1970). Ridge Regression: Biased Estimation for Nonorthogonal Problems. Technometrics, 12(1), 55 E7.
  • Tibshirani, R. (1996). Regression Shrinkage and Selection via the Lasso. Journal of the Royal Statistical Society: Series B, 58(1), 267 E88.
  • Zou, H., & Hastie, T. (2005). Regularization and Variable Selection via the Elastic Net. Journal of the Royal Statistical Society: Series B, 67(2), 301 E20.