Programming

규제 선형회귀(Regularized Linear Regression)와 Ridge 회귀 실습

Lucas.Kim 2026. 1. 5. 08:13
반응형

1. 규제 선형회귀 개요

앞서 다항회귀에서 degree=15와 같이 차수를 과도하게 늘렸을 때,
모든 데이터 포인트를 지나치게 정확히 맞추려는 과대적합(Overfitting) 이 발생했습니다.

이 경우 다음과 같은 문제가 나타납니다.

  • 회귀식이 지나치게 복잡해짐
  • 회귀계수(W)가 비정상적으로 커짐
  • 학습 데이터에는 잘 맞지만, 새로운 데이터에 대한 예측 성능 급격히 저하

이를 해결하기 위해 등장한 개념이 규제(Regularization) 입니다.

2. 규제의 핵심 아이디어

✔ 최적의 회귀 모델이란?

학습 데이터의 오차를 최소화하면서, 회귀계수의 크기도 적절히 제어하는 모델

이를 비용 함수(Cost Function) 관점에서 표현하면 다음과 같습니다.

Cost = RSS(오차) + α × (회귀계수 패널티)

 

  • RSS: 실제값과 예측값의 잔차 제곱합
  • α(alpha): 규제 강도를 조절하는 하이퍼파라미터

3. alpha 값의 역할

  • alpha → 0
    • 규제 효과 거의 없음
    • 일반 선형회귀(OLS)와 동일
    • 과적합 위험 증가
  • alpha → 커짐
    • 회귀계수 값이 0에 가까워짐
    • 모델 복잡도 감소
    • 과적합 완화

즉, alpha는 “데이터 적합 vs 모델 단순화”의 균형을 조절하는 손잡이입니다.

4. 규제 방식의 종류

L2 규제 – Ridge 회귀

  • 회귀계수의 제곱값에 패널티 부여
  • 계수를 0으로 만들지는 않지만 전반적으로 작게 만듦
  • 다중공선성 문제 완화에 효과적

L1 규제 – Lasso 회귀

  • 회귀계수의 절대값에 패널티 부여
  • 중요도가 낮은 계수를 0으로 만듦
  • 자동 피처 선택 효과

ElasticNet

  • L1 + L2 규제 결합
  • 피처 수가 많은 데이터에서 유용

이번 글에서는 Ridge 회귀(L2 규제) 에 집중합니다.

5. Ridge 회귀 실습 (Boston Housing 데이터)

5-1. 데이터 로딩 및 분리

from sklearn.model_selection import train_test_split
from sklearn.linear_model import Ridge
from sklearn.model_selection import cross_val_score
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt

column_list = ['CRIM', 'ZN', 'INDUS', 'CHAS', 'NOX', 'RM', 'AGE',
               'DIS', 'RAD', 'TAX', 'PTRATIO', 'B', 'LSTAT', 'PRICE']

# 보스턴 주택 가격 데이터 로딩
bostonDF = pd.read_csv(
    './bostondata/housing.csv',
    header=None,
    delimiter=r"\s+",
    names=column_list
)

print(f'California Housing 데이터 셋 크기 : {bostonDF.shape}')

# 피처(X)와 타겟(y) 분리
X_data = bostonDF.drop(['PRICE'], axis=1)
y_target = bostonDF['PRICE']

# 학습/테스트 데이터 분리
X_train, X_test, y_train, y_test = train_test_split(
    X_data,
    y_target,
    test_size=0.3,
    random_state=156
)

 

목적 설명

  • 회귀계수 분석을 위해 정규화되지 않은 원본 피처 사용
  • 이후 alpha 값 변화에 따른 계수 변화 확인이 핵심

5-2. Ridge 회귀 + 교차검증 평가

ridge = Ridge(alpha=10)  # 규제 강도 설정

# 5-Fold 교차검증으로 MSE 평가
neg_mse_scores = cross_val_score(
    ridge,
    X_data,
    y_target,
    scoring='neg_mean_squared_error',
    cv=5
)

# RMSE 계산
rmse_scores = np.sqrt(-1 * neg_mse_scores)
avg_rmse = np.mean(rmse_scores)

print(f'5fold MSE : {np.round(neg_mse_scores,3)}')
print(f'5fold 개별 RMSE scores : {np.round(rmse_scores, 3)}')
print(f'5fold 평균 RMSE scores : {np.round(avg_rmse, 3)}')

핵심 포인트

  • neg_mean_squared_error는 사이킷런 규칙상 음수로 반환
  • RMSE는 해석이 직관적이므로 비교 지표로 적합

5-3. alpha 값 변화에 따른 성능 비교

alphas = [0, 0.1, 1, 10, 100]

for alpha in alphas:
    ridge = Ridge(alpha=alpha)
    neg_mse_scores = cross_val_score(
        ridge,
        X_data,
        y_target,
        scoring='neg_mean_squared_error',
        cv=5
    )
    avg_rmse = np.mean(np.sqrt(-1 * neg_mse_scores))
    print(f'알파값 {alpha} 일때 RMSE 평균 : {avg_rmse}')

결과 해석

  • alpha 증가 → RMSE 감소
  • 규제가 과적합을 완화하며 일반화 성능 개선

6. alpha 값에 따른 회귀계수 변화 시각화

fig, axs = plt.subplots(figsize=(18,6), nrows=1, ncols=5)
coeff_df = pd.DataFrame()

for pos, alpha in enumerate(alphas):
    ridge = Ridge(alpha=alpha)
    ridge.fit(X_data, y_target)

    coeff = pd.Series(ridge.coef_, index=X_data.columns)
    colname = 'alpha:' + str(alpha)
    coeff_df[colname] = coeff

    coeff = coeff.sort_values(ascending=False)
    axs[pos].set_title(colname)
    axs[pos].set_xlim(-3, 6)
    sns.barplot(x=coeff.values, y=coeff.index, ax=axs[pos])

plt.show()

핵심 관찰

  • alpha가 커질수록 모든 회귀계수가 0에 가까워짐
  • 특정 피처에 과도하게 의존하던 구조가 완화됨

6-1. 계수 비교용 DataFrame 정렬

sort_column = 'alpha:' + str(alphas[0])
coeff_df.sort_values(by=sort_column, ascending=False)

의미

  • 규제가 없는(alpha=0) 상태에서 영향력이 큰 피처 기준으로 정렬
  • 이후 alpha 증가에 따른 계수 감소 패턴 비교 가능


7. 정리

  • Ridge 회귀는 과적합 + 다중공선성 문제에 효과적
  • alpha는 모델 복잡도와 예측 성능의 균형점
  • 실무에서는 교차검증 기반 alpha 튜닝 필수
  • 다항회귀와 결합 시 특히 중요
반응형