범주형 데이터(categorical features) 처리에 강점을 가짐.
Gradient Boosting 알고리즘들은 반복적으로 트리를 학습하면서 성능을 향상시키는 방식으로 동작함.
기존 부스팅 모델(XGBoost, LightGBM 등)은 Target Leakage(타깃 누출) 및 Prediction Shift(예측값 분포 이동) 문제를 가짐.
CatBoost는 이를 해결하기 위해 Ordered Target Statistics (OTS) 및 Ordered Boosting 기법을 도입함.
Gradient Boosting은 여러 개의 약한 학습기(Weak Learner, 보통 결정 트리)를 순차적으로 학습하여 성능을 점진적으로 향상시키는 앙상블 학습 기법
일반적으로 잔차(residuals)를 줄이는 방향으로 새로운 트리를 추가하며, 반복적인 업데이트 과정을 통해 최적의 모델을 구축
초기 예측값 설정:
모델의 초기 예측값은 타깃의 평균값으로 설정됨.
이후 업데이트 단계:
는 새롭게 추가되는 트리, 는 학습률 (Learning Rate)이며, 각 단계에서 모델이 오차를 보정하는 방향으로 업데이트됨.
각 단계에서 새로운 트리는 기존 모델의 잔차(residuals)를 최소화하는 방향으로 학습됨:
손실 함수 를 최적화함.
범주형 변수를 수치형으로 변환할 때, 전통적인 방법은 해당 범주 내 샘플들의 평균 타깃값을 사용하는 방식임.
CatBoost는 이를 해결하기 위해 순서 기반 타깃 통계(Ordered Target Statistics, OTS) 기법을 사용함.
기존 Gradient Boosting에서는 각 단계에서 새롭게 학습되는 트리가 이전 단계에서 계산된 예측값을 기반으로 학습함.
이전 모델이 훈련 데이터의 정답을 참조하여 예측값을 생성하기 때문에, 테스트 시에는 분포가 달라지는 문제가 발생함.
CatBoost는 Ordered Boosting 기법을 사용하여 Prediction Shift 문제를 해결함.
이 방법을 통해 부스팅 과정에서 자신이 훈련에 포함된 데이터라는 정보가 잔차 계산에 반영되지 않도록 설계됨.
| 데이터셋 | CatBoost (Logloss) | LightGBM 증가율 | XGBoost 증가율 |
|---|---|---|---|
| Adult | 0.2695 | +2.4% | +2.2% |
| Amazon | 0.1394 | +17% | +17% |
| Click | 0.3917 | +1.2% | +1.2% |
범주형 변수가 많은 데이터셋에서 차이가 더 크게 나타남.
CatBoost는 범주형 데이터를 다룰 때 강력한 성능을 발휘하는 Gradient Boosting 모델임.
Ordered TS 및 Ordered Boosting 기법을 통해 기존 Gradient Boosting 모델들의 한계를 극복하며, 다양한 머신러닝 문제에서 활용 가능함.
import numpy as np
import pandas as pd
from catboost import CatBoostRegressor, Pool
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error
import optuna
numpy와 pandas를 사용하여 데이터 생성 및 처리 catboost에서 CatBoostRegressor, Pool을 가져와 모델 학습 sklearn의 train_test_split, mean_squared_error를 사용하여 데이터 분할 및 성능 평가 optuna를 활용하여 하이퍼파라미터 최적화 def generate_data(n_samples=1000, n_features=10, random_state=42):
np.random.seed(random_state)
X = np.random.randn(n_samples, n_features) # 정규 분포를 따르는 랜덤 데이터 생성
y = X @ np.random.randn(n_features) + np.random.randn(n_samples) # 선형 관계에 노이즈 추가
return pd.DataFrame(X, columns=[f'feature_{i}' for i in range(n_features)]), y
n_samples 개의 샘플과 n_features 개의 특성을 가진 데이터 생성 y = X @ w + noise 형태로 선형 관계를 갖는 데이터 생성 X, y = generate_data()
X_train, X_valid, y_train, y_valid = train_test_split(X, y, test_size=0.2, random_state=42)
train_test_split을 사용하여 80:20 비율로 훈련 데이터와 검증 데이터로 분리 train_pool = Pool(X_train, y_train)
valid_pool = Pool(X_valid, y_valid)
Pool 객체 생성 (CatBoost에서 내부적으로 최적화된 데이터 구조) fit()을 사용할 때 Pool 객체를 사용하면 성능이 향상될 수 있음 def objective(trial):
params = {
'iterations': trial.suggest_int('iterations', 100, 1000),
'depth': trial.suggest_int('depth', 4, 10),
'learning_rate': trial.suggest_loguniform('learning_rate', 0.01, 0.3),
'l2_leaf_reg': trial.suggest_loguniform('l2_leaf_reg', 1e-1, 10.0),
'bagging_temperature': trial.suggest_uniform('bagging_temperature', 0.0, 1.0),
'random_strength': trial.suggest_uniform('random_strength', 0.0, 2.0),
'border_count': trial.suggest_int('border_count', 32, 255),
'boosting_type': trial.suggest_categorical('boosting_type', ['Ordered', 'Plain']),
'verbose': 0
}
trial.suggest_*()을 활용하여 하이퍼파라미터 탐색 범위 지정 iterations: 부스팅 반복 횟수 (100~1000) depth: 트리 깊이 (4~10) learning_rate: 학습률 (0.01~0.3, 로그 스케일) l2_leaf_reg: L2 정규화 계수 (0.1~10) bagging_temperature: 배깅 샘플링 비율 조정 (0~1) random_strength: 분할 시 무작위성 추가 (0~2) border_count: 연속형 변수를 이진화할 때 사용할 경계 개수 (32~255) boosting_type: Ordered(순서 기반) 또는 Plain(일반) 부스팅 설정 model = CatBoostRegressor(**params, random_seed=42)
model.fit(train_pool, eval_set=valid_pool, early_stopping_rounds=50, verbose=False)
early_stopping_rounds=50을 사용하여 50번 동안 개선이 없으면 학습 조기 종료 y_pred = model.predict(X_valid)
mse = mean_squared_error(y_valid, y_pred)
return mse
mse를 최소화하는 것이므로, MSE 값을 반환 study = optuna.create_study(direction='minimize')
study.optimize(objective, n_trials=50)
optuna.create_study()를 통해 MSE를 최소화하는 방향으로 탐색 설정 study.optimize()를 호출하여 50번의 실험을 통해 최적의 하이퍼파라미터 찾기 print('Best Parameters found', study.best_params)
best_params = study.best_params
final_model = CatBoostRegressor(**best_params, random_seed=42)
final_model.fit(train_pool, eval_set=valid_pool, early_stopping_rounds=50, verbose=False)
final_predictions = final_model.predict(X_valid)
final_mse = mean_squared_error(y_valid, final_predictions)
print(f'Final MSE: {final_mse:.5f}')
from lightgbm import LGBMRegressor
from xgboost import XGBRegressor
def objective(trial):
model_type = trial.suggest_categorical('model', ['CatBoost', 'LightGBM', 'XGBoost'])
model_type을 CatBoost, LightGBM, XGBoost 중에서 선택하도록 설정 if model_type == 'CatBoost':
model = CatBoostRegressor(**params, random_seed=42)
elif model_type == 'LightGBM':
model = LGBMRegressor(**params, random_state=42)
else:
model = XGBRegressor(**params, random_state=42)
model.fit(X_train, y_train, eval_set=[(X_valid, y_valid)], verbose=False)
y_pred = model.predict(X_valid)
mse = mean_squared_error(y_valid, y_pred)
return mse
study = optuna.create_study(direction='minimize')
study.optimize(objective, n_trials=50)
best_model_type = study.best_params.pop('model')
if best_model_type == 'CatBoost':
final_model = CatBoostRegressor(**best_params, random_seed=42)
elif best_model_type == 'LightGBM':
final_model = LGBMRegressor(**best_params, random_state=42)
else:
final_model = XGBRegressor(**best_params, random_state=42)
final_predictions = final_model.predict(X_valid)
final_mse = mean_squared_error(y_valid, final_predictions)
print(f'Final MSE : {final_mse:.5f}')
CatBoost, LightGBM, XGBoost를 비교하여 최적 모델을 찾고, 하이퍼파라미터 최적화를 수행함 Optuna를 활용하여 자동으로 최적의 파라미터를 탐색하고 성능을 향상시킴 CatBoost는 범주형 변수를 자동 처리하며 강력한 성능을 보이는 모델임 LightGBM, XGBoost와 함께 비교 실험을 통해 모델 선택 가능