앙상블 — 배깅 & 부스팅 & AdaBoost 실습 정리

syeom·2026년 5월 14일

멀티캠퍼스 데이터분석 5월 14일 수업 내용 — Bagging으로 호텔 예약 취소 예측, BaggingRegressor로 차량 가격 예측, AdaBoost 분류/회귀 실습


📌 목차

이론
1. 앙상블이란?
2. 배깅 (Bagging) — 이론 & 매개변수
3. 부스팅 (Boosting) — 이론 & 대표 알고리즘
4. AdaBoost — 이론 & 매개변수

실습

  1. BaggingClassifier — 호텔 예약 취소 예측
  2. BaggingRegressor — 차량 가격 예측
  3. AdaBoostClassifier — 신체 능력 등급 분류
  4. AdaBoostRegressor — 차량 가격 예측 & 학습 곡선

이론

1. 앙상블이란?

단일 결정 트리(DecisionTree)의 단점을 극복하기 위해 여러 머신러닝 모델을 연결하여 더 강력한 모델을 만드는 과정입니다.

여러 예측 모형 생성 → 예측 모형 조합 → 하나의 최종 모형 완성

대표 기법: 배깅, 부스팅, 랜덤 포레스트


2. 배깅 (Bagging) — 이론 & 매개변수

주어진 자료를 모집단으로 간주하고 부트스트랩(중복 허용 샘플링) 으로 여러 개의 데이터를 생성한 뒤 각각 모델을 학습시켜 결합합니다.

장점

  • 분산을 줄이고 과적합 완화
  • 안정적인 성능 보장
  • 비선형/노이즈 데이터에 강함

주요 매개변수

매개변수기본값설명
estimatorNone기본 모델 설정
n_estimators10생성할 모델 수
max_samples1.0각 모델이 사용할 샘플 비율
max_features1.0각 모델이 사용할 피처 비율
bootstrapTrue중복 샘플링 허용 여부
bootstrap_featuresFalse중복 컬럼 허용 여부
oob_scoreFalseOOB 데이터로 성능 평가 여부
n_jobsNone병렬 처리 CPU 수 (-1: 전체 사용)

주요 속성

속성설명
estimators_학습된 모델 리스트
estimators_samples_각 모델이 학습한 샘플 인덱스
estimators_features_각 모델이 학습한 컬럼 인덱스
oob_score_OOB 데이터 기반 정확도(분류) / R²(회귀)

💡 OOB(Out-Of-Bag) — 부트스트랩에서 선택되지 않은 데이터로, 별도의 test 셋 없이 성능 평가가 가능합니다.


3. 부스팅 (Boosting) — 이론 & 대표 알고리즘

모델을 순차적으로 학습하면서 이전 모델이 틀린 데이터에 가중치를 높여 다음 모델에서 집중 학습합니다.

장점 & 단점

내용
장점편향 감소 → 예측 확률 향상, 단순 모델들로 강력한 모델 생성
단점순차 학습으로 병렬화 어려움(속도 느림), 과적합 위험, 파라미터 튜닝 중요

대표 알고리즘

알고리즘설명
AdaBoost오차가 큰 샘플에 높은 가중치 부여, 가중치 합산으로 최종 결정
Gradient Boosting (GBM)이전 모델의 잔차를 예측하는 모델 추가, 손실 함수 직접 최적화
XGBoostGBM 개선, 규제+병렬 학습 지원, 대표적인 부스팅 알고리즘 (별도 설치 필요)
LightGBM히스토그램 기반 학습, 대용량 데이터에 특화, XGBoost보다 속도 우수
CatBoost범주형 데이터 자동 처리, 튜닝 비교적 간단

4. AdaBoost — 이론 & 매개변수

  • 초기에 모든 샘플의 가중치를 동일하게 부여
  • 약한 모델 학습 → 잘못 분류한 샘플의 가중치 증가 → 다음 모델에서 집중 학습 반복

주요 매개변수 (분류/회귀 공통)

매개변수기본값설명
estimatorDecisionTreeClassifier(max_depth=1)기본 모델
n_estimators50모델 개수 (많을수록 느림, 과적합 위험)
learning_rate1.0각 단계별 기여도 (작을수록 모델 수 증가 필요)
algorithm'SAMME.R'분류 알고리즘 (SAMME.R: 확률 기반 / SAMME: 점수 기반)

💡 learning_rate & n_estimators 상호 보완 관계

  • learning_rate ↓ → 각 단계 영향 줄어듦 → n_estimators ↑ 필요
  • 데이터가 크고 복잡 → learning_rate ↓ + n_estimators ↑
  • 데이터가 작음 → learning_rate ↑ + n_estimators ↓

주요 속성 (분류)

속성설명
estimators_학습된 모델 리스트
estimator_weights_각 모델의 가중치
estimator_errors_각 단계별 오차율
feature_importances_피처별 중요도 (가중치 합)

회귀에서의 loss 매개변수

설명
'linear'기본 선형 업데이트
'square'제곱 — 큰 오차에 더 민감
'exponential'지수 — 매우 큰 오차에 강한 패널티

실습

5. BaggingClassifier — 호텔 예약 취소 예측

데이터 로드 & 전처리

import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import BaggingClassifier
from sklearn.metrics import f1_score

hotel = pd.read_csv('../data/hotel_bookings.csv')

컬럼 설명

컬럼설명
is_canceled예약 취소 여부 (1: 취소, 0: 체크인) ← target
deposit_type보증금 유형
lead_time예약 시차 (예약일~체크인일)
stays_in_weekend_nights주말 숙박 일수
stays_in_week_nights평일 숙박 일수
is_repeated_guest재방문 고객 여부
previous_cancellation과거 취소 횟수
previous_bookings_not_canceled과거 정상 투숙 횟수
booking_changes예약 변경 횟수
days_in_waiting_list대기 명단에 있었던 횟수
adr1박당 평균 객실 요금
# adr 음수 데이터 제거
hotel = hotel.loc[~(hotel['adr'] < 0)]

# 결측치 처리
hotel['lead_time']         = hotel['lead_time'].fillna(hotel['lead_time'].mean())
hotel['adr']               = hotel['adr'].fillna(hotel['adr'].mean())
hotel['is_repeated_guest'] = hotel['is_repeated_guest'].fillna(
    hotel['is_repeated_guest'].value_counts().index[0]   # 최빈값
)

# deposit_type 더미 변수 생성
df = pd.get_dummies(hotel, columns=['deposit_type'], drop_first=True)

x = df.drop('is_canceled', axis=1)
y = df['is_canceled']

X_train, X_test, y_train, y_test = train_test_split(
    x, y, test_size=0.3, stratify=y, random_state=42
)

기본 BaggingClassifier — class_weight 적용

base_model = DecisionTreeClassifier(class_weight='balanced', max_depth=3)

model = BaggingClassifier(base_model, n_estimators=500)
model.fit(X_train, y_train)

pred = model.predict(X_test)
print(round(f1_score(y_test, pred), 4))

RandomOverSampler + BaggingClassifier

from imblearn.over_sampling import RandomOverSampler, SMOTE

# 2:1 비율로 오버샘플링
oversample = RandomOverSampler(sampling_strategy=0.5)
x_over, y_over = oversample.fit_resample(x, y)

X_train, X_test, y_train, y_test = train_test_split(
    x_over, y_over, test_size=0.3, random_state=42, stratify=y_over
)

clf = BaggingClassifier(
    estimator    = DecisionTreeClassifier(),
    n_estimators = 100,
    max_samples  = 0.8   # 각 모델이 80% 샘플만 사용
)
clf.fit(X_train, y_train)
pred = clf.predict(X_test)
print(round(f1_score(y_test, pred), 4))

SMOTE + BaggingClassifier

smote = SMOTE()
x_sm, y_sm = smote.fit_resample(x, y)

X_train, X_test, y_train, y_test = train_test_split(
    x_sm, y_sm, test_size=0.2, random_state=42, stratify=y_sm
)

clf2 = BaggingClassifier(estimator=DecisionTreeClassifier(), n_estimators=100)
clf2.fit(X_train, y_train)
pred2 = clf2.predict(X_test)
print(round(f1_score(y_test, pred2), 4))

OOB Score — 별도 Test 셋 없이 성능 평가

clf_oob = BaggingClassifier(
    estimator    = DecisionTreeClassifier(),
    n_estimators = 100,
    oob_score    = True
)
clf_oob.fit(x_over, y_over)
print(clf_oob.oob_score_)

6. BaggingRegressor — 차량 가격 예측

데이터 전처리 — 문자형 & 숫자형 분리

from sklearn.ensemble import BaggingRegressor
from sklearn.tree import DecisionTreeRegressor
from sklearn.metrics import mean_squared_error, r2_score, mean_absolute_error

car = pd.read_csv('../data/CarPrice_Assignment.csv')

# 타입별 분리
df_str = car.select_dtypes('object')
df_int = car.select_dtypes('number')

# doornumber — 문자 → 숫자
df_str['doornumber'] = df_str['doornumber'].map(lambda x: 2 if x == 'two' else 4)

# cylindernumber — 문자 → 숫자
df_str['cylindernumber'] = df_str['cylindernumber'].map({
    'four': 4, 'six': 6, 'five': 5, 'three': 3,
    'twelve': 12, 'two': 2, 'eight': 8
})

CarName — 브랜드 컬럼 분리

# 공백 기준으로 분리 후 brand, modelName 컬럼 생성
vals = df_str['CarName'].map(lambda x: x.split()).values
df_str[['brand', 'modelName']] = vals

# CarName, modelName 제거
df_str.drop(['CarName', 'modelName'], axis=1, inplace=True)

더미 변수 & 결합

# object 타입 컬럼 더미 변수 생성
cols   = df_str.select_dtypes('object').columns
df_str2 = pd.get_dummies(df_str, columns=cols, drop_first=True)

df_int.drop('car_ID', axis=1, inplace=True)

# 열 결합
df = pd.concat([df_str2, df_int], axis=1)

x = df.drop('price', axis=1)
y = df['price']

X_train, X_test, y_train, y_test = train_test_split(
    x, y, test_size=0.3, random_state=42
)

BaggingRegressor 학습 & 평가

reg = BaggingRegressor(
    estimator    = DecisionTreeRegressor(),
    n_estimators = 100,
    oob_score    = True
)
reg.fit(X_train, y_train)

print('OOB Score:', reg.oob_score_)

pred = reg.predict(X_test)

print('MAE :', round(mean_absolute_error(y_test, pred), 2))
print('MSE :', round(mean_squared_error(y_test, pred), 2))
print('R2  :', round(r2_score(y_test, pred), 2))

7. AdaBoostClassifier — 신체 능력 등급 분류

import numpy as np
from sklearn.ensemble import AdaBoostClassifier
from sklearn.metrics import classification_report

body = pd.read_csv('../data/bodyPerformance.csv')

body['gender'] = body['gender'].map({'M': 0, 'F': 1})
body['class']  = body['class'].map({'A': 1, 'B': 2, 'C': 3, 'D': 4})

x = body.drop('class', axis=1)
y = body['class']

X_train, X_test, y_train, y_test = train_test_split(
    x, y, test_size=0.2, random_state=42
)

기본 모델 vs 하이퍼파라미터 조정

# 기본 AdaBoost
clf = AdaBoostClassifier()
clf.fit(X_train, y_train)
print(classification_report(y_test, clf.predict(X_test)))

# n_estimators 증가 + learning_rate 감소
clf2 = AdaBoostClassifier(n_estimators=500, learning_rate=0.1)
clf2.fit(X_train, y_train)
print(classification_report(y_test, clf2.predict(X_test)))

# 기본 모델을 DecisionTree(max_depth=4)로 변경
from sklearn.tree import DecisionTreeClassifier

clf3 = AdaBoostClassifier(
    estimator    = DecisionTreeClassifier(max_depth=4),
    n_estimators = 500,
    learning_rate= 0.1
)
clf3.fit(X_train, y_train)
print(classification_report(y_test, clf3.predict(X_test)))

💡 classification_report() — 클래스별 precision, recall, f1-score, support를 한 번에 출력합니다.

피처 중요도 확인

importances = clf3.feature_importances_

feature_df = pd.DataFrame(
    zip(x.columns, importances),
    columns=['feature_name', 'importance']
)

feature_df.sort_values('importance', ascending=False).head()

8. AdaBoostRegressor — 차량 가격 예측 & 학습 곡선

학습 & 평가

import matplotlib.pyplot as plt
from sklearn.ensemble import AdaBoostRegressor
from sklearn.metrics import mean_absolute_error, r2_score

car = pd.read_csv('../data/CarPrice_Assignment.csv')
df  = car.select_dtypes('number').drop('car_ID', axis=1)

x = df.drop('price', axis=1)
y = df['price']

X_train, X_test, y_train, y_test = train_test_split(
    x, y, test_size=0.3, random_state=42
)

# 기본 모델
reg = AdaBoostRegressor()
reg.fit(X_train, y_train)
pred = reg.predict(X_test)
print('MAE :', round(mean_absolute_error(y_test, pred), 2))
print('R2  :', round(r2_score(y_test, pred), 2))

# 하이퍼파라미터 조정
reg2 = AdaBoostRegressor(n_estimators=500, learning_rate=0.1)
reg2.fit(X_train, y_train)
pred2 = reg2.predict(X_test)
print('MAE :', round(mean_absolute_error(y_test, pred2), 2))
print('R2  :', round(r2_score(y_test, pred2), 2))

staged_predict() — 단계별 MAE 학습 곡선

mae_list = []

for stage_pred in reg2.staged_predict(X_test):
    # 각 단계별 예측값으로 MAE 계산
    mae_list.append(mean_absolute_error(y_test, stage_pred))

plt.figure(figsize=(16, 8))
plt.plot(mae_list)
plt.xlabel('Count')
plt.ylabel('MAE')
plt.show()

💡 staged_predict(X) — 각 단계별 누적 모델의 예측값을 순차적으로 반환합니다.
학습 진행에 따라 MAE가 어떻게 변화하는지 학습 곡선으로 확인할 수 있습니다.

피처 중요도 수평 막대 그래프

importance_df = pd.DataFrame(
    zip(x.columns, reg2.feature_importances_),
    columns=['feature_name', 'importance']
)
importance_df.sort_values('importance', ascending=False, inplace=True)

plt.figure(figsize=(16, 8))
plt.barh(importance_df['feature_name'].tail(), importance_df['importance'].tail())
plt.show()

📎 핵심 개념 요약

개념설명
앙상블여러 모델을 결합해 강력한 모델 생성
배깅병렬 학습 → 분산 감소, 과적합 완화
부스팅순차 학습 → 편향 감소, 이전 오차 집중 학습
OOB Score부트스트랩에서 선택 안 된 데이터로 성능 평가
oob_score=True별도 Test 셋 없이 일반화 성능 확인
n_estimators생성할 모델 수
max_samples각 모델이 사용할 샘플 비율
learning_rate각 단계 기여도 — n_estimators와 상호 보완
feature_importances_피처별 중요도 (합계 = 1)
staged_predict()단계별 누적 예측값 반환 → 학습 곡선 확인
classification_report()클래스별 precision/recall/f1 한번에 출력
select_dtypes('object')특정 타입의 컬럼만 선택
pd.concat([df1, df2], axis=1)열 방향 결합
profile
공부 기록

0개의 댓글