머신 러닝 (25) Cat Boost Classification

 import pandas as pd

import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.datasets import fetch_openml
from sklearn.model_selection import train_test_split, StratifiedKFold, GridSearchCV
from catboost import CatBoostClassifier
from sklearn.metrics import accuracy_score, classification_report

print("Loading Pima Indians Diabetes Dataset...")
pima = fetch_openml(name='diabetes', version=1, as_frame=True)
X = pima.data
y = pima.target.map({'tested_negative': 0, 'tested_positive': 1}).astype(int)

print(f"데이터 크기: {X.shape}")
print(f"피처 목록: {list(X.columns)}")
print(f"\n클래스 분포:\n{y.value_counts()}")

# 데이터 샘플
print("\n데이터 샘플:")
print(X.head())

print("\n기술 통계:")
print(X.describe())

# 데이터 분리 (stratify로 클래스 비율 유지)
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42, stratify=y
)

print(f"Train: {X_train.shape}, Test: {X_test.shape}")
print(f"\nTrain 클래스 분포:\n{y_train.value_counts()}")

# 기본 모델 생성
cat_clf = CatBoostClassifier(
    iterations=100,
    learning_rate=0.1,
    depth=6,
    random_state=42,
    verbose=0  # 학습 로그 비활성화
)

# 학습
cat_clf.fit(X_train, y_train)

# 예측
y_pred = cat_clf.predict(X_test)

# 평가
train_acc = cat_clf.score(X_train, y_train)
test_acc = accuracy_score(y_test, y_pred)

print("="*50)
print("기본 CatBoost Classifier 결과")
print("="*50)
print(f"Train Accuracy: {train_acc:.4f}")
print(f"Test Accuracy: {test_acc:.4f}")
print(f"\n분류 리포트:\n{classification_report(y_test, y_pred)}")

# 하이퍼파라미터 그리드 정의
param_grid = {
    'iterations': [100, 150, 200],
    'learning_rate': [0.01, 0.05, 0.1],
    'depth': [4, 6, 8],
    'l2_leaf_reg': [1, 3, 5]
}

print("파라미터 그리드:")
for key, value in param_grid.items():
    print(f"  {key}: {value}")

# 총 조합 수
total_combinations = np.prod([len(v) for v in param_grid.values()])
print(f"\n총 파라미터 조합: {total_combinations}개")

# StratifiedKFold 설정
skf = StratifiedKFold(n_splits=3, shuffle=True, random_state=42)

# GridSearchCV 생성
grid_clf = GridSearchCV(
    estimator=CatBoostClassifier(random_state=42, verbose=0),
    param_grid=param_grid,
    cv=skf,
    scoring='accuracy',
    n_jobs=-1,
    verbose=1
)

print("GridSearchCV 생성완료...\n")

grid_clf.fit(X_train, y_train)

# 최적 파라미터 출력
print("="*50)
print("최적 하이퍼파라미터")
print("="*50)
for param, value in grid_clf.best_params_.items():
    print(f"{param:20s}: {value}")

print(f"\n최적 CV Score: {grid_clf.best_score_:.4f}")

# 최적 모델 저장
best_clf = grid_clf.best_estimator_

# 테스트 데이터 예측
y_pred_best = best_clf.predict(X_test)

# 성능 평가
train_acc_best = best_clf.score(X_train, y_train)
test_acc_best = accuracy_score(y_test, y_pred_best)

print("="*50)
print("최적화된 CatBoost 결과")
print("="*50)
print(f"Train Accuracy: {train_acc_best:.4f}")
print(f"Test Accuracy: {test_acc_best:.4f}")
print(f"\n분류 리포트:\n{classification_report(y_test, y_pred_best)}")

# 성능 비교 데이터프레임
comparison = pd.DataFrame({
    'Model': ['Default CatBoost', 'Tuned CatBoost'],
    'Train Acc': [train_acc, train_acc_best],
    'Test Acc': [test_acc, test_acc_best]
})

print("\n성능 비교:")
print(comparison.to_string(index=False))

# 시각화
fig, ax = plt.subplots(1, 1, figsize=(6, 4))

x = np.arange(len(comparison))
width = 0.35

ax.bar(x - width/2, comparison['Train Acc'], width, label='Train', alpha=0.8)
ax.bar(x + width/2, comparison['Test Acc'], width, label='Test', alpha=0.8)

ax.set_ylabel('Accuracy')
ax.set_title('CatBoost Performance Comparison')
ax.set_xticks(x)
ax.set_xticklabels(comparison['Model'])
ax.legend()
ax.set_ylim([0.6, 1.0])

# 값 표시
for i, v in enumerate(comparison['Train Acc']):
    ax.text(i - width/2, v + 0.01, f'{v:.4f}', ha='center', va='bottom', fontsize=9)
for i, v in enumerate(comparison['Test Acc']):
    ax.text(i + width/2, v + 0.01, f'{v:.4f}', ha='center', va='bottom', fontsize=9)

plt.tight_layout()
plt.show()

# 피처 중요도 추출
importances = best_clf.get_feature_importance()
feature_names = X.columns
indices = np.argsort(importances)[::-1]

# 중요도 정렬
importance_df = pd.DataFrame({
    'Feature': feature_names[indices],
    'Importance': importances[indices]
})

print("\n피처 중요도 순위:")
print(importance_df.to_string(index=False))

# 시각화
plt.figure(figsize=(6, 4))
sns.barplot(x=importances[indices], y=feature_names[indices], palette='viridis')
plt.title("Feature Importances (CatBoost)")
plt.xlabel("Importance")
plt.ylabel("Features")
plt.tight_layout()
plt.show()

# Early Stopping with eval_set
cat_early = CatBoostClassifier(
    **grid_clf.best_params_,
    early_stopping_rounds=10,
    random_state=42,
    verbose=0
)

# Validation set 분리
X_tr, X_val, y_tr, y_val = train_test_split(
    X_train, y_train, test_size=0.2, random_state=42, stratify=y_train
)

# 학습 (eval_set 제공)
cat_early.fit(
    X_tr, y_tr,
    eval_set=(X_val, y_val),
    verbose=False
)

print(f"\nEarly Stopping:")
print(f"최적 트리 개수: {cat_early.get_best_iteration() + 1}")
print(f"설정 트리 개수: {grid_clf.best_params_['iterations']}")
print(f"Test Accuracy: {cat_early.score(X_test, y_test):.4f}")

print("\n" + "="*50)
print("CatBoost Classification 완료")
print("="*50)

print(f"\n최종 성능:")
print(f"  - 기본 모델 정확도: {test_acc:.4f}")
print(f"  - 최적화 모델 정확도: {test_acc_best:.4f}")
print(f"  - 성능 향상: {(test_acc_best - test_acc)*100:+.2f}%p")

print(f"\n최적 파라미터:")
for param, value in grid_clf.best_params_.items():
    print(f"  - {param}: {value}")

print(f"\nTop 3 중요 피처:")
for i in range(min(3, len(importance_df))):
    print(f"  {i+1}. {importance_df.iloc[i]['Feature']}: {importance_df.iloc[i]['Importance']:.4f}")

print("\n" + "="*50)

댓글

이 블로그의 인기 게시물

베이스 캠프에서 (1)

베이스 캠프에서 (2)

Database 분석 (4)