본문 바로가기
개발/Python

과대적합 해결 방법

by 피로물든딸기 2025. 10. 8.
반응형

전체 링크

 

과소적합

- 모델이 데이터의 패턴을 충분히 배우지 못한 상태

- 학습 데이터와 테스트 데이터 모두에서 성능이 낮음

- 학습 데이터가 불충분, 중요한 특성을 사용하지 않은 상태

 

과대적합

- 학습 데이터의 성능이 높고, 평가 데이터의 성능은 낮은 상태 (노이즈까지 학습한 상태)

- 학습 데이터의 패턴을 지나치게 학습하여 편향이 낮아진 상태

- 데이터의 작은 변화에도 민감하게 반응 → 분산이 높은 상태


선형 회귀

→ Ridge / Lasso 규제 추가

import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression, Ridge, Lasso
from sklearn.preprocessing import PolynomialFeatures
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error

# 1. 데이터 생성
np.random.seed(0)
X = np.linspace(0, 1, 50)[:, np.newaxis]       # 0~1 사이 50개
y = np.sin(2 * np.pi * X).ravel() + np.random.randn(50) * 0.3  # 노이즈 포함

# 2. 다항특성 생성 (과대적합 유발)
poly = PolynomialFeatures(degree=15)  # 15차 다항식 -> 과대적합
X_poly = poly.fit_transform(X)

# 3. 학습/테스트 데이터 분리
X_train, X_test, y_train, y_test = train_test_split(X_poly, y, test_size=0.2, random_state=42)

# 4. 모델 학습
# 4-1. Linear Regression (과대적합)
lr = LinearRegression()
lr.fit(X_train, y_train)
y_train_pred = lr.predict(X_train)
y_test_pred = lr.predict(X_test)

# 4-2. Ridge Regression
ridge = Ridge(alpha=1.0)
ridge.fit(X_train, y_train)
y_ridge_pred = ridge.predict(X_test)

# 4-3. Lasso Regression
lasso = Lasso(alpha=0.01, max_iter=10000)
lasso.fit(X_train, y_train)
y_lasso_pred = lasso.predict(X_test)

# 5. 결과 확인
print("Linear Regression MSE (train/test):", mean_squared_error(y_train, y_train_pred), "/", mean_squared_error(y_test, y_test_pred))
print("Ridge MSE (test):", mean_squared_error(y_test, y_ridge_pred))
print("Lasso MSE (test):", mean_squared_error(y_test, y_lasso_pred))

# 6. 시각화
plt.figure(figsize=(12,6))
plt.scatter(X, y, color='black', label='data')
plt.plot(X, lr.predict(X_poly), label='Linear Regression', color='red')
plt.plot(X, ridge.predict(X_poly), label='Ridge', color='blue')
plt.plot(X, lasso.predict(X_poly), label='Lasso', color='green')
plt.legend()
plt.show()


Ridge / Lasso

- λ (또는 α) ↑ (크게)

- 규제 강도를 높이면 가중치가 작아져 모델 단순화

import numpy as np
import matplotlib.pyplot as plt
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import Ridge, Lasso
from sklearn.model_selection import train_test_split

# 1. 데이터 생성
np.random.seed(0)
X = np.linspace(0, 1, 30)[:, np.newaxis]
y = np.sin(2 * np.pi * X).ravel() + np.random.randn(30) * 0.3

# 2. 다항특성 생성 (10차 다항식)
poly = PolynomialFeatures(degree=10)
X_poly = poly.fit_transform(X)

# 3. 학습/테스트 분리
X_train, X_test, y_train, y_test = train_test_split(X_poly, y, test_size=0.3, random_state=42)

# 4. α 값 리스트
alphas = [10, 1, 0.1, 0.01, 0.0001]

# 5. 시각화
plt.figure(figsize=(14,6))

for i, alpha in enumerate(alphas):
    # Ridge
    ridge = Ridge(alpha=alpha)
    ridge.fit(X_train, y_train)
    y_ridge_pred = ridge.predict(X_poly)
    
    # Lasso
    lasso = Lasso(alpha=alpha, max_iter=10000)
    lasso.fit(X_train, y_train)
    y_lasso_pred = lasso.predict(X_poly)
    
    # Plot Ridge
    plt.subplot(2, len(alphas), i+1)
    plt.scatter(X, y, color='black')
    plt.plot(X, y_ridge_pred, color='blue')
    plt.title(f'Ridge α={alpha}')
    
    # Plot Lasso
    plt.subplot(2, len(alphas), i+1+len(alphas))
    plt.scatter(X, y, color='black')
    plt.plot(X, y_lasso_pred, color='green')
    plt.title(f'Lasso α={alpha}')

plt.tight_layout()
plt.show()

 


Logistic Regression

- C ↓ : 규제 강도의 역수, 작아지면 규제가 강해지고 → 과대적합 완화

- 규제 L1, L2 추가


SVM

- C (규제 강도), gamma (커널 영향 범위) 를 감소

 

SVC

import numpy as np
import matplotlib.pyplot as plt
from sklearn.svm import SVC
from sklearn.datasets import make_moons

# 2차원 분류 데이터 생성
X, y = make_moons(n_samples=200, noise=0.2, random_state=42)

# C와 gamma 후보
C_values = [0.1, 1, 10]
gamma_values = [0.1, 1, 10]

plt.figure(figsize=(12, 12))

# 3x3 그리드로 그리기
for i, C in enumerate(C_values):
    for j, gamma in enumerate(gamma_values):
        svc = SVC(C=C, gamma=gamma)
        svc.fit(X, y)
        
        # 결정 경계 그리기
        x_min, x_max = X[:, 0].min() - 0.5, X[:, 0].max() + 0.5
        y_min, y_max = X[:, 1].min() - 0.5, X[:, 1].max() + 0.5
        xx, yy = np.meshgrid(np.linspace(x_min, x_max, 200),
                             np.linspace(y_min, y_max, 200))
        Z = svc.predict(np.c_[xx.ravel(), yy.ravel()]).reshape(xx.shape)
        
        plt.subplot(3, 3, i*3 + j + 1)
        plt.contourf(xx, yy, Z, alpha=0.3, cmap=plt.cm.coolwarm)
        plt.scatter(X[:, 0], X[:, 1], c=y, s=30, cmap=plt.cm.coolwarm, edgecolors='k')
        plt.title(f"C={C}, gamma={gamma}")
        plt.xlim(xx.min(), xx.max())
        plt.ylim(yy.min(), yy.max())

plt.tight_layout()
plt.show()

 

SVR

import numpy as np
import matplotlib.pyplot as plt
from sklearn.svm import SVR

# 샘플 데이터 생성
X = np.sort(5 * np.random.rand(100, 1), axis=0)
y = np.sin(X).ravel() + 0.2 * np.random.randn(100)

# C와 gamma 후보
C_values = [0.1, 1, 10]
gamma_values = [0.1, 1, 10]

plt.figure(figsize=(12, 12))
X_plot = np.linspace(0, 5, 100).reshape(-1, 1)

# 3x3 그리드로 그리기
for i, C in enumerate(C_values):
    for j, gamma in enumerate(gamma_values):
        svr = SVR(C=C, gamma=gamma)
        svr.fit(X, y)
        y_pred = svr.predict(X_plot)
        
        plt.subplot(3, 3, i*3 + j + 1)
        plt.scatter(X, y, color='darkorange', label='data')
        plt.plot(X_plot, y_pred, color='navy', lw=2, label='SVR fit')
        plt.title(f"C={C}, gamma={gamma}")
        plt.ylim(-2, 2)
        if i == 2 and j == 0:
            plt.legend()

plt.tight_layout()
plt.show()


K-NN

- k ↑ (이웃 수 늘리기) → 분산 감소, 이웃이 많을수록 모델이 덜 민감

- 거리 가중 평균 사용

import numpy as np
from sklearn.datasets import make_moons
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import accuracy_score
import matplotlib.pyplot as plt

# 1. 데이터 생성
X, y = make_moons(n_samples=300, noise=0.25, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

# 2. 과대적합 K-NN (k=1)
knn_overfit = KNeighborsClassifier(n_neighbors=1)
knn_overfit.fit(X_train, y_train)
y_pred_overfit = knn_overfit.predict(X_test)
print("과대적합 K-NN (k=1) 정확도:", accuracy_score(y_test, y_pred_overfit))

# 3. 과대적합 해소 K-NN (k=15, 거리 가중치)
knn_regularized = KNeighborsClassifier(n_neighbors=15, weights='distance')
knn_regularized.fit(X_train, y_train)
y_pred_regularized = knn_regularized.predict(X_test)
print("과대적합 해소 K-NN (k=15, 거리 가중치) 정확도:", accuracy_score(y_test, y_pred_regularized))

# 4. 시각화 (가로로 비교)
def plot_knn_comparison(knn1, knn2, X, y, title1, title2):
    fig, axes = plt.subplots(1, 2, figsize=(12,5))  # 가로 2개
    x_min, x_max = X[:,0].min()-0.5, X[:,0].max()+0.5
    y_min, y_max = X[:,1].min()-0.5, X[:,1].max()+0.5
    xx, yy = np.meshgrid(np.linspace(x_min, x_max, 200),
                         np.linspace(y_min, y_max, 200))
    
    for ax, knn, title in zip(axes, [knn1, knn2], [title1, title2]):
        Z = knn.predict(np.c_[xx.ravel(), yy.ravel()]).reshape(xx.shape)
        ax.contourf(xx, yy, Z, alpha=0.3, cmap=plt.cm.coolwarm)
        ax.scatter(X[:,0], X[:,1], c=y, cmap=plt.cm.coolwarm, edgecolors='k')
        ax.set_title(title)
    plt.show()

plot_knn_comparison(
    knn_overfit, knn_regularized, X, y,
    "K-NN (k=1)", "K-NN (k=15)"
)


Decision Tree

- max_depth ↓ : 트리가 너무 깊어지면 학습 데이터에만 맞춤

- max_features ↓ : 일부 특징만 보고 분할하면 트리가 덜 복잡해짐
- max_leaf_nodes ↓ : 리프가 많으면 학습 데이터에 지나치게 맞춤

- min_samples_split ↑ : 너무 작은 수치로 나누면 트리가 깊어짐

- min_samples_leaf ↑ : 작은 노드가 생기는 걸 방지

- min_weight_fraction_leaf ↑ : 노드가 너무 작아지는 걸 방지

- min_impurity_decrease ↑ : 불순도 감소가 충분하지 않으면 분할하지 않음

- ccp_alpha ↑ : 트리 가지치기 강화

 

Random Forest

- n_estimators ↑ : 과적합 감소, 일반화 안정화

 

AdaBoost 

- n_estimators ↓ : 이전 학습기의 오류를 다음 학습기가 학습 (모델이 학습 데이터에 과도하게 맞춰져 과대적합 발생)

- learning_rate ↓ : 너무 크면 한 학습기가 결과에 큰 영향을 주어 빠르게 학습 → 과대적합 위험이 증가

 

Gradient Boosting

- n_estimators ↓ : 이전 트리의 오류를 다음 트리가 학습 → 트리가 많을수록 과대적합 발생

- learning_rate ↓ : 너무 크면 한 학습기가 결과에 큰 영향을 주어 빠르게 학습

- subsample ↓ : 전체 데이터를 사용하지 않고 일부만 학습 → 모델의 분산 줄이고 과대적합 완화

- alpha ↓ : 이상치로 인한 과도한 학습 억제

- validation_fraction ↑ : 검증용 데이터가 충분히 있어야 학습 조기 종료 가능

 

XGBoost

- learning_rate ↓ : 낮출수록 트리가 조금씩 학습 → 과대적합 완화

n_estimators ↓ : 부스팅 → 트리가 많을수록 과대적합 발생

- gamma ↑ : 노드를 분할하기 위해 필요한 최소 손실 감소량, 값이 크면 노드 분할 제한 → 과대적합 완화

- min_child_weight ↑ : 값이 작으면 노드가 쉽게 분할 → 과대적합

- subsample ↓ : 각 트리를 학습할 때 데이터 일부만 사용 → 분산 감소, 과대적합 완화

- colsample_bytree ↓ : 각 트리를 학습할 때 데이터 일부만 사용 → 분산 감소, 과대적합 완화

- colsample_bylevel ↓ : 각 레벨의 분할에서 컬럼 샘플링 비율 → 분산 감소, 과대적합 완화

- reg_alpha ↑ : 모델 복잡도를 낮추고, 작은 가중치를 0으로 만든다. (L1)

- reg_lambda ↑ : 트리의 리프(weight)를 학습할 때, 값이 너무 커지지 않도록 패널티 부여


심층신경망

- 네트워크 복잡도 제어

- 드롭아웃 : 학습 과정에서 일부 뉴런을 제거, 평가 단계에서는 모든 뉴런 활성화 → 훈련 속도만 감소

- 배치 정규화 : 각 층의 입력 분포가 변경되지 않도록 정규화

- 규제 강화 : 모델의 가중치를 규제, 손실 함수에 페널티 추가

- Early Stopping : 학습 중 성능이 개선되지 않으면 학습을 중지

 

나이브 베이즈

- alpha ↑ : alpha가 커질수록 모델이 더 평균적인 확률을 쓰게 되어 과대적합 완화

 

군집 모델 (Kmeans, 병합 군집)

- n_clusters ↓ : 너무 많이 잡아서 데이터에 너무 정확히 맞추는 경우 → 과대적합

 

차원축소

- PCA, AutoEncoder의 차원 수 감소 (더 적은 차원으로 표현해야 단순한 모델)

 

Gaussian Mixture Model (GMM)

- 복잡한 분포를 단순화

- 컴포넌트 수 ↓

- 공분산 형태 제한

 

베이지안 회귀 (Bayesian Regression)

- 사전 확률로 가중치 범위 제한

- Prior 분포를 강하게 설정

반응형

'개발 > Python' 카테고리의 다른 글

불균형 데이터 처리  (0) 2025.10.08
Batch Normalization vs Layer Normalization  (0) 2025.10.08
이미지 생성형 AI 모델  (0) 2025.10.06
주요 합성곱 신경망  (0) 2025.10.06
경사 하강법, 옵티마이저  (0) 2025.10.06

댓글