본문 바로가기
개발/Python

XGBoost Hyper Parameters and Attributes

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

전체 링크

XGBoost

Gradient Boosting 기반(+ 최적화와 정규화)의 결정 트리 앙상블 알고리즘

- 여러 개의 약한 결정 트리(weak learners)를 순차적으로 학습시켜 오류를 점점 줄이는 방식

- 병렬 처리 가능 → 학습 속도 빠름

- 과적합 방지를 위한 정규화 기능 포함

- 결측치 처리 가능, 다양한 평가 지표 지원

- 대규모 데이터 처리에도 효율적

 

장점

- 높은 정확도

- 결측치 자동 처리

- 빠른 학습과 예측

- 과적합 방지 기능 내장

 

단점

- 모델 해석이 어려움

- 매우 큰 데이터셋에서는 메모리 사용량 증가

- 하이퍼 파라미터 튜닝이 필요


하이퍼 파라미터

from xgboost import XGBClassifier, XGBRegressor

XGBClassifier(
    max_depth=3,
    learning_rate=0.1,
    n_estimators=100,
    silent=True,
    objective='binary:logistic',
    booster='gbtree',
    n_jobs=1,
    nthread=None,
    gamma=0,
    min_child_weight=1,
    max_delta_step=0,
    subsample=1,
    colsample_bytree=1,
    colsample_bylevel=1,
    reg_alpha=0,
    reg_lambda=1,
    scale_pos_weight=1,
    base_score=0.5,
    random_state=0,
    seed=None,
    missing=None,
    **kwargs,
)

XGBRegressor(
    max_depth=3,
    learning_rate=0.1,
    n_estimators=100,
    silent=True,
    objective='reg:linear',
    booster='gbtree',
    n_jobs=1,
    nthread=None,
    gamma=0,
    min_child_weight=1,
    max_delta_step=0,
    subsample=1,
    colsample_bytree=1,
    colsample_bylevel=1,
    reg_alpha=0,
    reg_lambda=1,
    scale_pos_weight=1,
    base_score=0.5,
    random_state=0,
    seed=None,
    missing=None,
    **kwargs,
)

max_depth

- 기본 학습기의 최대 트리 깊이

- 결정트리와 동일

import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_moons
from xgboost import XGBClassifier
from matplotlib.colors import ListedColormap

# 2차원 예제 데이터 생성
X, y = make_moons(n_samples=300, noise=0.25, random_state=42)

models = {
    "max_depth=2": XGBClassifier(max_depth=2, n_estimators=50, use_label_encoder=False, eval_metric='logloss'),
    "max_depth=10": XGBClassifier(max_depth=10, n_estimators=50, use_label_encoder=False, eval_metric='logloss')
}

# 결정 경계 시각화 함수
def plot_decision_boundary(model, X, y, ax, title):
    model.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, 300),
                         np.linspace(y_min, y_max, 300))
    Z = model.predict(np.c_[xx.ravel(), yy.ravel()]).reshape(xx.shape)
    
    cmap_light = ListedColormap(['#FFAAAA', '#AAAAFF'])
    cmap_bold = ListedColormap(['#FF0000', '#0000FF'])
    
    ax.contourf(xx, yy, Z, alpha=0.3, cmap=cmap_light)
    ax.scatter(X[:, 0], X[:, 1], c=y, cmap=cmap_bold, edgecolor='k', s=50)
    ax.set_title(title)

# 그림 그리기
fig, axes = plt.subplots(1, 2, figsize=(12, 5))
for ax, (title, model) in zip(axes, models.items()):
    plot_decision_boundary(model, X, y, ax, title)

plt.show()


learning_rate

- 부스팅 학습률(Boosting Learning Rate)을 조절하는 하이퍼파라미터

- 여러 개의 트리를 순차적으로 학습해서 오류를 줄여나가는 방식

- 각 단계에서 새로운 트리는 이전 트리들의 잔차(residual)를 학습

- 이때 새로 만든 트리가 학습 과정에서 얼마나 크게 기여할지를 조절하는 것이 eta (learning_rate)

- eta가 작을수록 한 트리가 모델에 기여하는 정도가 작아지고, 학습이 느려지지만 일반화 성능이 좋아질 가능성이 높음

- 일반적으로: 0.01 ~ 0.3 사이에서 조정

import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_moons
from xgboost import XGBClassifier
from matplotlib.colors import ListedColormap

# 2차원 예제 데이터 생성
X, y = make_moons(n_samples=300, noise=0.25, random_state=42)

models = {
    "max_depth=2": XGBClassifier(max_depth=2, n_estimators=50, use_label_encoder=False, eval_metric='logloss'),
    "max_depth=10": XGBClassifier(max_depth=10, n_estimators=50, use_label_encoder=False, eval_metric='logloss')
}

# 결정 경계 시각화 함수
def plot_decision_boundary(model, X, y, ax, title):
    model.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, 300),
                         np.linspace(y_min, y_max, 300))
    Z = model.predict(np.c_[xx.ravel(), yy.ravel()]).reshape(xx.shape)
    
    cmap_light = ListedColormap(['#FFAAAA', '#AAAAFF'])
    cmap_bold = ListedColormap(['#FF0000', '#0000FF'])
    
    ax.contourf(xx, yy, Z, alpha=0.3, cmap=cmap_light)
    ax.scatter(X[:, 0], X[:, 1], c=y, cmap=cmap_bold, edgecolor='k', s=50)
    ax.set_title(title)

# 그림 그리기
fig, axes = plt.subplots(1, 2, figsize=(12, 5))
for ax, (title, model) in zip(axes, models.items()):
    plot_decision_boundary(model, X, y, ax, title)

plt.show()

 

→ learning_rate가 작을수록 일반화 성능이 높다. (과적합 방지)


n_estimators

- 학습할 부스팅 트리 수


objective : str 또는 callable

- 학습 작업 및 대응 학습 목표 지정, 또는 사용자 정의 목적 함수

- 사용자 정의 함수일 경우, 아래 형식을 따른다.


booster : str

- 사용할 부스터 유형 지정: 'gbtree', 'gblinear', 'dart'


gamma : float

- 리프 노드에서 추가 분할을 수행하기 위한 최소 손실 감소

- gamma가 클수록 분할 조건이 엄격해지고, 트리가 덜 깊고 단순하다.

- gamma = 0 → 작은 이득도 분할 허용 → 트리 복잡도 ↑

- 0 ~ 5 정도로 설정

import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_moons
from xgboost import XGBClassifier

# 2차원 복잡한 데이터 (moons)
X, y = make_moons(n_samples=500, noise=0.3, random_state=42)

# gamma 값 리스트
gamma_values = [0, 5, 30]

# meshgrid 준비
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.arange(x_min, x_max, 0.01),
                     np.arange(y_min, y_max, 0.01))

plt.figure(figsize=(18,5))

for i, gamma_val in enumerate(gamma_values):
    # 모델 학습
    clf = XGBClassifier(n_estimators=50, max_depth=3, gamma=gamma_val,
                        use_label_encoder=False, eval_metric='logloss')
    clf.fit(X, y)
    
    # 결정 경계 계산
    Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])
    Z = Z.reshape(xx.shape)
    
    # 그래프
    plt.subplot(1, 3, i+1)
    plt.contourf(xx, yy, Z, alpha=0.4, cmap=plt.cm.RdYlBu)
    plt.scatter(X[:,0], X[:,1], c=y, cmap=plt.cm.RdYlBu, edgecolor='k')
    plt.title(f'XGBoost Decision Boundary (gamma={gamma_val})')
    plt.xlabel('Feature 1')
    plt.ylabel('Feature 2')

plt.tight_layout()
plt.show()

 

gamma가 작을수록 과대적합되고 있는 것을 알 수 있다.


min_child_weight : int

- 자식 노드에서 필요한 최소 인스턴스 가중치 합계

- 트리의 자식 노드가 가지는 최소한의 샘플 가중치 합

- 이 값보다 작으면 해당 노드는 더 이상 분할되지 않음

- min_child_weight ↑ → 자식 노드 최소 샘플 수 증가 → 트리 단순화, 과적합 방지

- min_child_weight ↓ → 작은 노드도 분할 허용 → 트리 복잡, 과적합 가능

 

- 결정 트리의 min_samples_leaf / min_samples_split와 유사

- 1 ~ 10 사이에서 설정

import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_moons
from xgboost import XGBClassifier

# 2차원 데이터 생성
X, y = make_moons(n_samples=500, noise=0.3, random_state=42)

# min_child_weight 값 리스트
child_weights = [1, 10, 20]

# meshgrid 준비
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.arange(x_min, x_max, 0.01),
                     np.arange(y_min, y_max, 0.01))

plt.figure(figsize=(18,5))

for i, weight in enumerate(child_weights):
    # 모델 학습
    clf = XGBClassifier(
        n_estimators=50,
        max_depth=3,
        min_child_weight=weight,
        use_label_encoder=False,
        eval_metric='logloss'
    )
    clf.fit(X, y)
    
    # 결정 경계 계산
    Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])
    Z = Z.reshape(xx.shape)
    
    # 그래프
    plt.subplot(1, 3, i+1)
    plt.contourf(xx, yy, Z, alpha=0.4, cmap=plt.cm.RdYlBu)
    plt.scatter(X[:,0], X[:,1], c=y, cmap=plt.cm.RdYlBu, edgecolor='k')
    plt.title(f'XGBoost Decision Boundary (min_child_weight={weight})')
    plt.xlabel('Feature 1')
    plt.ylabel('Feature 2')

plt.tight_layout()
plt.show()

 

min_child_weight=1 → 작은 노드도 분할 → 결정 경계 세밀, 과적합 가능

min_child_weight=5 → 일부 작은 분할 억제 → 경계 조금 단순화

min_child_weight=20 → 작은 노드 거의 분할 안 함 → 경계 단순, 과적합 감소

 

min_child_weight가 작을수록 과대적합되고 있는 것을 알 수 있다.


max_delta_step : int

- 각 트리 가중치 추정 시 허용되는 최대 델타 스텝

- 각 leaf의 weight 최대 변화량 제한

- 한 단계에서 가중치가 너무 크게 변하지 않도록 안정화

- 학습이 너무 급격하게 진행되는 것을 방지

- 불균형/불안정 학습 안정화

- leaf output 변화 제한 ↑ → 학습 안정 ↑, 학습 속도 ↓

 

ex. 클래스 불균형 문제

- 작은 클래스의 gradient가 크면 학습이 불안정할 수 있음

- max_delta_step=1~10 정도 설정으로 안정화


subsample : float

- 학습 인스턴스의 샘플링 비율

- 값 범위 : 0 ~ 1

- 사용하는 데이터가 줄어들기 때문에 훈련 속도가 빨라짐

효과 : 과적합 방지, 일반화 향상

주의 : 너무 낮으면 학습 불안정, 너무 높으면 과적합

 

ex.

- subsample=0.6 → 트리 학습 시 데이터의 60%만 랜덤 선택

- 데이터 1000개, subsample=0.6

- 첫 번째 트리 학습 → 600개 샘플 사용

- 두 번째 트리 학습 → 또 다른 600개 샘플 랜덤 선택


colsample_bytree : float

- 각 트리를 구성할 때 컬럼 샘플링 비율

- 값 범위 : 0 ~ 1

- 각 트리를 학습할 때 전체 피처 중 일부만 사용

- 효과 : 과적합 방지, 랜덤성 증가

- 트리마다 선택되는 피처가 달라서 앙상블 다양성 증가

 

ex.

- 데이터 10개 피처, colsample_bytree=0.5

- 첫 번째 트리 → 10개 피처 중 5개만 선택

- 두 번째 트리 → 다른 5개 피처 선택 가능

 

colsample_bylevel : float

- 각 레벨의 분할에서 컬럼 샘플링 비율

- 값 범위 : 0 ~ 1

- 트리의 각 레벨(split)마다 사용할 피처 비율 조절

- 더 세밀한 샘플링으로 과적합 방지

- colsample_bytree와 함께 사용하면 트리 단위 + 레벨 단위 샘플링 가능

- 트리 내부에서 레벨별로 다른 피처를 허용 → 같은 트리 안에서도 다양한 구조를 만듦

- 고차원(특징 많은) 데이터에서 유용할 수 있음

import matplotlib.pyplot as plt
from sklearn.datasets import make_classification
from xgboost import XGBClassifier
import numpy as np

# Generate dataset
X, y = make_classification(
    n_samples=600,
    n_features=2,
    n_redundant=0,
    n_clusters_per_class=1,
    class_sep=1.2,
    random_state=0
)

# Grid
xx, yy = np.meshgrid(
    np.linspace(X[:, 0].min()-1, X[:, 0].max()+1, 300),
    np.linspace(X[:, 1].min()-1, X[:, 1].max()+1, 300)
)

col_vals0 = [1.0, 0.7, 0.5]
col_vals1 = [1.0, 0.7, 0.5]

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

plot_idx = 1
for s in col_vals0:
    for c in col_vals1:
        model = XGBClassifier(
            colsample_bytree=s,
            colsample_bylevel=c,
            n_estimators=40,
            max_depth=3,
            learning_rate=0.1,
            use_label_encoder=False,
            eval_metric="logloss"
        )
        model.fit(X, y)

        Z = model.predict(np.c_[xx.ravel(), yy.ravel()])
        Z = Z.reshape(xx.shape)

        plt.subplot(len(sub_vals), len(col_vals), plot_idx)
        plt.contourf(xx, yy, Z, alpha=0.3)
        plt.scatter(X[:, 0], X[:, 1], c=y, s=10)
        plt.title(f"bytree={s}, bylevel={c}")
        plt.xlabel("X1")
        plt.ylabel("X2")

        plot_idx += 1

plt.tight_layout()
plt.show()

 

bytree

- 트리 간의 다양성 증가

- 트리 하나가 만들어지는 동안 한 번만 피처 서브셋을 랜덤하게 선택

- 하나의 트리에서는 같은 피처를 보고 분할

 

bylevel

- 같은 트리 안에서 다양한 구조

- 레벨마다 랜덤한 관점에서 분할 (ex. level 0에서는 f1 ~ f3만 보고 분할, level 1에서는 f3 ~ f5를 보고 분할)


reg_alpha : float

- 가중치에 대한 L1 정규화 항

- 가중치 절댓값 합을 최소화하는 규제

- 값이 커질수록 일부 트리의 잎사귀(weight)가 0이 되어 특징 선택 효과와 과적합 감소

- reg_alpha ↑ → 모델 희소(sparse)화, 일부 잎사귀 무시

 

reg_lambda : float

- 가중치에 대한 L2 정규화 항

- 가중치 제곱합을 최소화하는 규제

- 값이 커질수록 모든 가중치가 작아짐, 과적합 감소, 더 부드러운 모델

- reg_lambda ↑ → 모델 전체 가중치 축소, 덜 과적합


scale_pos_weight : float

- 양성 / 음성 클래스 가중치 조정

- 클래스 불균형(class imbalance)을 조정할 때 사용

 

- 값 > 1: positive 클래스(1)에 더 큰 가중치 → 모델이 positive를 더 잘 맞추도록 유도

- 값 < 1: positive 클래스 중요도를 낮춤 (rarely 사용)

 

- 불균형 비율 계산 후 적용 → scale_pos_weight = (#negative) / (#positive)

from xgboost import XGBClassifier
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report

# 극단적으로 불균형 데이터 생성 (positive 5%, negative 95%)
X, y = make_classification(
    n_samples=500,
    n_features=5,
    n_informative=3,
    n_redundant=0,
    n_clusters_per_class=1,
    weights=[0.95, 0.05],
    flip_y=0,
    random_state=42
)

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

# scale_pos_weight 비교
for spw in [1, 19]:  # negative/positive = 0.95/0.05 ~ 19
    model = XGBClassifier(
        scale_pos_weight=spw,
        use_label_encoder=False,
        eval_metric='logloss',
        n_estimators=1000,
        max_depth=3,
        learning_rate=0.1,
        random_state=42
    )
    model.fit(X_train, y_train)
    y_pred = model.predict(X_test)
    print(f"=== scale_pos_weight={spw} ===")
    print(classification_report(y_test, y_pred))

 

 minority 클래스(positive)를 더 잘 맞추도록 모델이 학습

→ 모델이 minority class(positive)를 더 많이 맞추려 시도

Recall ↑ (positive를 놓치는 경우가 줄어듦)

 

→ False Positive 증가 가능Precision ↓

→ 왜냐하면 모델이 positive로 더 적극적으로 예측하면서 틀린 것도 포함될 수 있음


base_score : float

- 모든 인스턴스의 초기 예측 점수, 전역 편향

- XGBoost는 잔차(residual) 학습 방식으로 트리를 쌓는데,

→ 초기 예측값 = base_score

→ 첫 번째 트리: 실제 값 - base_score 차이(잔차)를 학습

→ 두 번째 트리: 첫 번째 트리 예측값 잔차 학습

→ …

→ 즉, base_score는 첫 트리가 맞추려는 목표의 출발점 역할을 한다.

 

- 트리 학습 자체에는 큰 영향을 주지 않지만 학습 속도와 초기 잔차 규모에 영향

- 불균형 데이터에서 positive / negative 비율에 맞춰 주면 첫 트리가 더 안정적으로 학습

 

불균형 클래스에서 positive 비율이 낮은 데이터의 경우

- base_score=0.5 → 첫 트리의 잔차가 positive는 +0.5, negative는 -0.5
→ positive 영향력이 상대적으로 작음

 

- base_score=positive 비율 (ex. 0.1)

→ 첫 트리 잔차 positive +0.9, negative -0.1
→ 소수 클래스 영향력이 더 커짐

→ 학습 초기부터 불균형 보정

반응형

댓글