AI/Machine Learning

[Machine Learning] 라쏘, 릿지, 엘라스틱넷 (Ridge, Lasso, ElasticNet)

byunghyun23 2022. 9. 28. 19:32

회귀 분석에는 제약식을 포함할 수 있습니다. 제약이 없다면 측정하려는 가중치 W가 기하급수적으로 커질 수 있으며 이로 인해 분산이 커지는 문제가 발생하게 됩니다.

이를 해결하기 위해 여러가지 제약식을 사용할 수 있습니다.

 

1. 라쏘 회귀(Lasso Regression) - L1 Regularization

라쏘 회귀는 L1 Loss 형태인 |θ|를 제약식으로 추가하여 특성값의 가중치가 극히 낮은 값이면 0으로 수렴하게 하여 특성을 제거하는 방법입니다. 특성을 0으로 만든다는 것은 상대적으로 bias를 증가시켜 오버피팅을 방지할 수 있습니다.

2. 릿지 회귀(Ridge Regression) - L2 Regularization

릿지 회귀는 L2 Loss 형태인 θ^2를 제약식으로 추가하여 모델 예측에 영향을 거의 미치지 않는 특성에 0에 가까운 가중치를 주는 방법입니다.

3. 엘라스틱넷(ElasticNet)

엘라스틱넷은 라쏘 회귀와 릿지 회귀의 최적화 지점이 서로 다르기 때문에 두 제약식(정규화)항을 합쳐서 가중치 r로 제약 정도를 조절하는 방법입니다.

 

결국 위 세 가지 가중치 제약 회귀 방법은 회귀 가중치의 값이 커져서 오버피팅을 방지하기 위한 방법이라고 볼 수 있습니다. (가중치 값이 커지는 것을 제한)

 

정리하면 특성의 수가 많고 그 중 일부분만 중요한 특성이라면 라쏘를,

특성의 중요도가 전체적으로 비슷하다면 릿지가 좀 더 좋은 모델을 만들기에 좋습니다.

또한 데이터의 수가 많고 라쏘와 릿지를 모두 반영하고 싶다면 엘라스틱넷을 사용할 수 있습니다.

 

사이킷런의 Lasso, Ridge, ElasticNet 클래스를 사용해 보겠습니다.

from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LinearRegression, Lasso, Ridge, ElasticNet
from sklearn.metrics import mean_squared_error

raw_boston = datasets.load_boston()

X = raw_boston.data
y = raw_boston.target
# X.shape, y.shape: (506, 13) (506,)

X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=1)
# X_train.shape, X_test.shape, y_train.shape, y_test.shape: (379, 13) (127, 13) (379,) (127,)

std_scaler = StandardScaler()
X_train = std_scaler.fit_transform(X_train)
X_test = std_scaler.transform(X_test)

lasso = Lasso()
ridge = Ridge()
elastic_net = ElasticNet()

lasso.fit(X_train, y_train)
ridge.fit(X_train, y_train)
elastic_net.fit(X_train, y_train)

print(lasso.coef_)
# [-0.          0.         -0.          0.         -0.          1.98095526
#  -0.         -0.         -0.         -0.         -1.35346816  0.
#  -3.88203158]
print(lasso.intercept_)
# 22.344591029023764

print(ridge.coef_)
# [-1.05933451  1.31050717  0.23022789  0.66955241 -2.45607567  1.99086611
#   0.18119169 -3.09919804  2.56480813 -1.71116799 -2.12002592  0.56264409
#  -4.00942448]
print(ridge.intercept_)
# 22.344591029023768

print(elastic_net.coef_)
# [-0.41185619  0.12517736 -0.242448    0.35325324 -0.43649162  1.96540308
#  -0.02116576 -0.         -0.         -0.16013619 -1.2626002   0.32546709
#  -2.36558977]
print(elastic_net.intercept_)
# 22.34459102902376

pred_lasso = lasso.predict(X_test)
pred_ridge = ridge.predict(X_test)
pred_elastic_net = elastic_net.predict(X_test)

lasso_mse = mean_squared_error(y_test, pred_lasso)
# 32.74719740278476

ridge_mse = mean_squared_error(y_test, pred_ridge)
# 21.894849212618745

elastic_net_mse = mean_squared_error(y_test, pred_elastic_net)
# 35.196183733607924

coef_를 통한 lasso의 회귀 계수(가중치)를 보면 0인 값이 보입니다.

이와 다르게 ridge의 회귀 계수에는 0이 없습니다.

또한 elastic_net의 회귀 계수에는 0인 값이 있긴 하지만 lasso보다는 그 수가 적습니다.