0. 과적합을 예방하기 위한 세가지 방법
보통 과소적합보다는 과적합의 문제가 많이 발생한다.
① 더 많은 데이터 학습시키기. 데이터 크기가 클수록 더 복잡한 모델을 쓸 수 있기 때문이다.
② 모든 특성을 사용하지 않는다. 중요한 특성 위주로 단순화
③ 정규화 모델. 모델에 규제항을 더해 기존 모델보다 단순화
1. 정규화 회귀모델이란?
선형모델에 규제항을 더해 과적합을 방지하는 방법. Regularized가 번역상 정규화가 되었지만 사실 규제를 한다는 뜻.
규제항은 회귀계수를 감소시켜 예측에 미치는 영향력을 축소시킨다. 그래서 모델이 학습데이터에 덜 적합하게 만들고 일반화 성능을 높인다. 편향을 더하고 분산을 줄이는 방식이다.
규제항의 종류에 따라 ridge, lasso, elasticNet으로 구분된다.
① ridge regression
회귀계수에 '가중치들의 제곱합'을 페널티로 부과.
② lasso regression
회귀계수의 가'중치들의 절대값의 합'을 페널티로 부과.
③ elasticnet regression
회귀계수에 가중치의 절대값의 합과 제곱합 두가지 모두를 페널티로 부과.
*패널티 (lambda)
alpha를 이용해 패널티의 강도를 조절할 수 있다. 이 강도가 높아질수록 기울기가 작아지고 들쑥날쑥한 선이 완만한 곡선으로 바뀐다. 그렇기에 이상치 영향도 덜 받고, 과적합도 줄일 수 있다. 이 패널티의 적정한 값을 찾아주는 함수도 있다.
2. 정규화 회귀모델을 만들기 전 EDA 단계
① 스케일링 - 수치형 특성
# 수치형 변수만 스케일링
numeric_feats = X_train.dtypes[X_train.dtypes != "object"].index
scaler = StandardScaler()
x_train[numeric_feats] = scaler.fit_transform(x_train[numeric_feats])
x_test[numeric_feats] = scaler.transform(x_test[numeric_feats])
# x_train에 scaler를 맞춘 후 나머지 val·test 데이터셋 등에 적용
# train에는 fit_trasform, val·test에는 transform
② 인코딩 - 범주형 특성
'gender'라는 특성이 있을 때 통상 Wenen과 men으로 나뉜다. 이 범주형 특성을 수치형 특성으로 바꾸어준다. gender_1과 gender_2 컬럼이 생긴다. gender_1에는 해당 데이터가 여성이면 1, 여성이 아니라면 0이 입력된다.
*다중공선성의 문제 조심
# One-Hot encoding
from category_encoders import OneHotEncoder
ohe = OneHotEncoder()
x_train_ohe = ohe.fit_transform(x_train)
x_test_ohe = ohe.transform(x_test)
# fit_trasform과 transform 사용이 위의 스케일링과 같다
*One-Hot Encoding 후 컬럼이 1000개가 넘어가는 등 과다하게 추가될 수 있다. 이 역시 과적합의 원인이 될 수 있으니 유의해야
③ 컬럼별 상관관계 확인
# 상관계수 함수
# dtype이 object인 컬럼에는 적용되지 않는다
df.corr()
# 범주형 컬럼과 타겟과의 관계
# 박스플롯으로 확인
fig = plt.figure()
fig.set_size_inches(24, 12)
(ax1, ax2, ax3), (ax4, ax5, ax6) = fig.subplots(nrows=2, ncols=3)
sns.boxplot(data=df, x='feature1', y='target', ax=ax1)
ax1.set_title('target - feature1')
sns.boxplot(data=df, x='feature2', y='target', ax=ax2)
ax2.set_title('target - feature2')
sns.boxplot(data=df, x='feature3', y='target', ax=ax3)
ax3.set_title('target - feature3')
# 수치형 컬럼과 타겟과의 관계
# 산점도로 확인
sns.scatterplot(data=df, x='feature4', y='target', ax=ax4)
ax4.set_title('target - feature4')
sns.scatterplot(data=df, x='feature5', y='target', ax=ax5)
ax5.set_title('target - feature5')
sns.scatterplot(data=df, x='feature6', y='SalePrice', ax=ax6)
ax6.set_title('target - feature6')
*그외
- 결측치 많은 컬럼 삭제
- 고유한 값이 너무 많은 컬럼도 삭제
3. 정규화 회귀모델
과적합이 발생했을 때 특성을 정리해주면 도움이 된다. 우리가 수동으로 필요한 컬럼과 필요치 않은 컬럼을 찾으려면 너무 많은 노력이 든다. 경우에 따라 특성이 200~1000개가 있을 수도 있기 때문이다.
모델은 피처마다 회귀계수를 만들어 예측을 하기위해 노력한다. ridge는 영향력이 적은 컬럼에 제약을 주어 회귀계수를 0에 가깝도록 낮추고, lasso는 영향력이 적은 컬럼의 회귀계수를 0으로 만드는 것을 통해 과적합을 해결한다.
*ridge와 lasso 중에 뭐가 더 좋은 방법일까? 이는 그때그때 달라서 실험을 해보아야한다.
# Ridge 모델 생성
from sklearn.linear_model import RidgeCV, LassoCV
# 먼저 RidgeCV를 활용해 적절한 alpha값을 찾는다
alphas = np.arange(1, 100, 10)
ridge = RidgeCV(alphas=alphas, cv=5)
ridge.fit(x_train_ohe, y_train)
# 모델과 적정 alpha값 출력
print(ridge)
print("alpha: ", ridge.alpha_)
# Lasso 모델 생성
# 적절한 alpha값을 찾는다
alphas = np.arange(1, 100, 10)
lasso = LassoCV(alphas=alphas, cv=5)
lasso.fit(x_train_ohe, y_train)
# 모델과 적정 alpha값 출력
print(lasso)
print("alpha: ", lasso.alpha_)
*또 다른 방법 - sklearn.feature_selection.SelectKbest
가장 효율적인 피처를 입력한 k값 만큼 골라내어 학습에 이용. 피처 수가 줄어들지만 과적합이 해소되고 test 결과값이 올라간다. 정규화 회귀모델이라고는 할 수 없고, 그냥 피처를 정리해주어 과적합을 방지해준다고 이해하면 된다.
'Codestates AI 부트캠프 > 2. Machine Learning' 카테고리의 다른 글
[머신러닝] 2-2 Boosting (1) | 2023.04.16 |
---|---|
[머신러닝] 2-1 Tree Based Model (0) | 2023.04.16 |
[머신러닝] 1-4 로지스틱 회귀 (Logistic Regression) (0) | 2023.04.16 |
[머신러닝] 1-2 일반화 (Generalization) (0) | 2023.03.23 |
[머신러닝] 1-1 Linear Regression (0) | 2023.03.23 |