CatBoost چیست؟ آموزش کامل یادگیری ماشین با دادههای دستهای در پایتون
آموزش عملی CatBoost با پایتون برای ساخت مدل روی دادههای عددی و دستهای؛ همراه با پروژه کامل، Early Stopping، انتخاب Threshold، Feature Importance، SHAP، ذخیره مدل و اتصال نتیجه به API درواره.
CatBoost یکی از قدرتمندترین کتابخانههای یادگیری ماشین برای کار با دادههای جدولی، بهویژه دادههایی است که ستونهای دستهای یا Categorical زیادی دارند.
در بسیاری از پروژههای واقعی با ستونهایی مانند نوع اشتراک، شهر، دستگاه، کانال جذب، دسته محصول، صنعت، کمپین و وضعیت کاربر روبهرو هستیم. الگوریتمهای سنتی معمولاً قبل از آموزش به تبدیل این ستونها با روشهایی مانند One-hot Encoding نیاز دارند؛ اما CatBoost میتواند بسیاری از ویژگیهای دستهای را مستقیماً پردازش کند.
این قابلیت باعث میشود Pipeline پروژه سادهتر شود، تعداد ستونهای مصنوعی کاهش پیدا کند و خطر بعضی از خطاهای رایج در Encoding نیز کمتر شود.
در این آموزش یک پروژه کامل طبقهبندی میسازیم که شامل مراحل زیر است:
- نصب CatBoost
- ساخت داده آزمایشی عددی و دستهای
- تقسیم Train، Validation و Test
- ساخت
Pool - آموزش
CatBoostClassifier - استفاده از Early Stopping
- ارزیابی داده نامتوازن
- انتخاب Threshold
- تحلیل Feature Importance
- محاسبه SHAP Values
- ذخیره و بارگذاری مدل
- پیشبینی روی رکورد جدید
- تنظیم Hyperparameterها
- اتصال نتیجه مدل به API درواره
- آمادهسازی برای استفاده در Production
CatBoost چیست؟
نام CatBoost از ترکیب دو عبارت Categorical و Boosting ساخته شده است. CatBoost یک الگوریتم Gradient Boosting مبتنی بر درخت تصمیم است که برای طبقهبندی، رگرسیون، رتبهبندی و مسائل دیگر یادگیری ماشین استفاده میشود.
در Gradient Boosting، چندین درخت بهصورت مرحلهای ساخته میشوند. هر درخت جدید تلاش میکند بخشی از خطاهای مدل فعلی را اصلاح کند:
Prediction =
Initial value
+ Learning rate × Tree 1
+ Learning rate × Tree 2
+ ...
+ Learning rate × Tree N
ویژگی مهم CatBoost، شیوه پردازش دادههای دستهای و استفاده از Ordered Boosting است. مقاله اصلی CatBoost، Ordered Boosting و روش پردازش Categorical Features را از نوآوریهای کلیدی این الگوریتم معرفی میکند. جزئیات فنی آن در مقاله علمی CatBoost قابل مطالعه است.
چرا CatBoost برای دادههای دستهای مناسب است؟
فرض کنید دیتاست شما چنین ستونهایی دارد:
| ستون | نوع |
|---|---|
monthly_sessions | عددی |
days_since_signup | عددی |
plan | دستهای |
device | دستهای |
industry | دستهای |
acquisition_channel | دستهای |
campaign_group | دستهای |
در روش One-hot Encoding، هر مقدار دستهای به یک ستون جداگانه تبدیل میشود. اگر ستون campaign_group صدها مقدار داشته باشد، تعداد ویژگیها بهسرعت افزایش پیدا میکند.
CatBoost میتواند نام ستونهای دستهای را دریافت و آنها را در فرایند آموزش مدیریت کند:
categorical_features = [
"plan",
"device",
"industry",
"acquisition_channel",
"campaign_group",
]
طبق مستندات رسمی ویژگیهای دستهای CatBoost، انجام One-hot Encoding دستی پیش از CatBoost توصیه نمیشود؛ زیرا ممکن است روی سرعت آموزش و کیفیت مدل اثر منفی بگذارد.
CatBoost برای چه کاربردهایی مناسب است؟
CatBoost بیشتر در پروژههایی کاربرد دارد که دادهها ساختاریافته و جدولی هستند:
- پیشبینی احتمال انجام یک رویداد
- طبقهبندی کاربران یا رکوردها
- تحلیل رفتار کاربران یک نرمافزار
- پیشبینی تقاضا
- امتیازدهی به سرنخهای فروش
- دستهبندی محصولات
- رتبهبندی نتایج
- پیشبینی مقدار عددی
- تحلیل دادههای دارای Category زیاد
- ترکیب ویژگیهای عددی و دستهای
- ساخت مدل روی ویژگیهای استخراجشده از متن
CatBoost یک مدل مولد نیست. این کتابخانه متن، تصویر یا ویدئو تولید نمیکند. برای دادههای غیرساختاریافته باید ابتدا ویژگی عددی یا Embedding استخراج شود.
مزایای CatBoost
مهمترین مزایای CatBoost عبارتاند از:
- پشتیبانی مستقیم از Categorical Features
- کاهش نیاز به One-hot Encoding
- سازگاری با رابط Scikit-learn
- پشتیبانی از CPU و GPU
- Early Stopping داخلی
- پشتیبانی از Feature Importance و SHAP
- امکان پردازش ویژگیهای متنی و Embedding
- ذخیره مدل در فرمت Native
- عملکرد مناسب روی بسیاری از دیتاستهای جدولی
- امکانات داخلی برای Grid Search و Randomized Search
پیادهسازی CatBoostClassifier از الگوی Estimator در Scikit-learn پیروی میکند و امکانات آموزش، پیشبینی و محاسبه اهمیت ویژگیها را ارائه میدهد. اطلاعات کامل در مستندات CatBoostClassifier موجود است.
محدودیتهای CatBoost
CatBoost در تمام پروژهها بهترین گزینه نیست:
- آموزش آن روی بعضی دیتاستها ممکن است از LightGBM کندتر باشد.
- مدلهای نهایی میتوانند حجم قابلتوجهی داشته باشند.
- روی دیتاست بسیار کوچک احتمال Overfitting وجود دارد.
- برای متن، تصویر و صوت خام جایگزین مدلهای تخصصی نیست.
- پردازش Categoryها نیازمند حفظ دقیق نوع داده و نام ستونها است.
- نتیجه مدل باید روی داده واقعی و Test مستقل ارزیابی شود.
- توضیحپذیری خروجی همچنان محدودیتهای مدلهای درختی را دارد.
بهتر است CatBoost را با یک Baseline ساده و الگوریتمهایی مانند Random Forest، XGBoost و LightGBM مقایسه کنید.
مقایسه CatBoost با LightGBM و XGBoost
| ویژگی | CatBoost | LightGBM | XGBoost |
|---|---|---|---|
| تمرکز اصلی | دادههای دستهای | سرعت روی داده بزرگ | مدل عمومی و قدرتمند جدولی |
| پردازش Category | داخلی و قدرتمند | پشتیبانی مستقیم | پشتیبانی مستقیم در نسخههای جدید |
| نیاز به One-hot Encoding | معمولاً خیر | معمولاً خیر | بسته به Workflow |
| سرعت آموزش | بالا | معمولاً بسیار بالا | بالا |
| حساسیت به تنظیم پارامتر | متوسط | نسبتاً زیاد | نسبتاً زیاد |
| GPU | پشتیبانی میشود | پشتیبانی میشود | پشتیبانی میشود |
| Early Stopping | داخلی | با Callback | داخلی |
| SHAP | داخلی | داخلی یا کتابخانه SHAP | داخلی یا کتابخانه SHAP |
| گزینه مناسب برای شروع | داده دارای Category زیاد | داده بزرگ و عددی | داده جدولی عمومی |
هیچکدام از این ابزارها در همه شرایط برنده نیستند. انتخاب نهایی باید بر اساس کیفیت داده، زمان آموزش، Latency، هزینه زیرساخت و معیارهای Test انجام شود.
نصب CatBoost
برای نصب CatBoost:
pip install catboost
وابستگیهای کامل این پروژه:
pip install catboost scikit-learn pandas numpy matplotlib requests
بررسی نسخه نصبشده:
python -c "import catboost; print(catboost.__version__)"
ساخت محیط مجازی
ایجاد Virtual Environment:
python -m venv .venv
فعالسازی در Windows PowerShell:
.venv\Scripts\Activate.ps1
فعالسازی در Linux و macOS:
source .venv/bin/activate
نصب وابستگیها:
python -m pip install --upgrade pip
python -m pip install catboost scikit-learn pandas numpy matplotlib requests
ساختار پیشنهادی پروژه
catboost-project/
├── .venv/
├── artifacts/
├── train.py
├── predict.py
└── requirements.txt
محتوای requirements.txt:
catboost
scikit-learn
pandas
numpy
matplotlib
requests
پروژه عملی: پیشبینی تکمیل فرایند فعالسازی
در این پروژه یک دیتاست مصنوعی از رفتار کاربران یک نرمافزار میسازیم. هدف مدل، پیشبینی احتمال تکمیل یک فرایند فرضی فعالسازی است.
ویژگیهای عددی:
- تعداد Sessionها
- تعداد روز از ثبتنام
- تعداد قابلیتهای استفادهشده
- میانگین زمان Session
- تعداد مراجعه به راهنما
- تعداد درخواستهای پشتیبانی
ویژگیهای دستهای:
- نوع پلن
- پلتفرم
- کانال جذب
- صنعت
- گروه کمپین
تمام دادهها مصنوعی هستند و هیچ اطلاعات شخصی یا واقعی در مثال استفاده نمیشود.
Import کردن کتابخانهها
فایل train.py را ایجاد کنید:
from pathlib import Path
import json
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from catboost import (
CatBoostClassifier,
Pool,
)
from sklearn.metrics import (
accuracy_score,
average_precision_score,
classification_report,
confusion_matrix,
f1_score,
precision_score,
recall_score,
roc_auc_score,
)
from sklearn.model_selection import (
train_test_split,
)
ساخت دیتاست مصنوعی
RANDOM_STATE = 42
def create_dataset(
number_of_rows: int = 10000,
) -> tuple[
pd.DataFrame,
pd.Series,
list[str],
]:
rng = np.random.default_rng(
RANDOM_STATE
)
data = pd.DataFrame(
{
"monthly_sessions": rng.poisson(
lam=10,
size=number_of_rows,
),
"days_since_signup": rng.integers(
low=1,
high=91,
size=number_of_rows,
),
"used_features": rng.integers(
low=0,
high=16,
size=number_of_rows,
),
"average_session_minutes": rng.gamma(
shape=2.2,
scale=5.0,
size=number_of_rows,
),
"help_page_visits": rng.poisson(
lam=2.0,
size=number_of_rows,
),
"support_requests": rng.poisson(
lam=0.8,
size=number_of_rows,
),
"plan": rng.choice(
[
"free",
"basic",
"pro",
"team",
],
size=number_of_rows,
p=[
0.35,
0.35,
0.20,
0.10,
],
),
"platform": rng.choice(
[
"web",
"android",
"ios",
"desktop",
],
size=number_of_rows,
p=[
0.50,
0.25,
0.17,
0.08,
],
),
"acquisition_channel": rng.choice(
[
"organic",
"direct",
"referral",
"campaign",
"content",
],
size=number_of_rows,
p=[
0.28,
0.24,
0.14,
0.18,
0.16,
],
),
"industry": rng.choice(
[
"software",
"retail",
"education",
"content",
"services",
"other",
],
size=number_of_rows,
),
"campaign_group": rng.choice(
[
f"campaign_{index:02d}"
for index in range(30)
],
size=number_of_rows,
),
}
)
plan_effect = (
data["plan"]
.map(
{
"free": -0.25,
"basic": 0.10,
"pro": 0.55,
"team": 0.75,
}
)
.astype(float)
)
channel_effect = (
data["acquisition_channel"]
.map(
{
"organic": 0.25,
"direct": 0.20,
"referral": 0.50,
"campaign": -0.05,
"content": 0.30,
}
)
.astype(float)
)
platform_effect = (
data["platform"]
.map(
{
"web": 0.25,
"android": 0.05,
"ios": 0.10,
"desktop": 0.20,
}
)
.astype(float)
)
noise = rng.normal(
loc=0.0,
scale=0.85,
size=number_of_rows,
)
raw_score = (
-3.2
+ 0.075 * data["monthly_sessions"]
+ 0.105 * data["used_features"]
+ 0.025 * data[
"average_session_minutes"
]
- 0.012 * data["days_since_signup"]
+ 0.030 * data["help_page_visits"]
- 0.20 * data["support_requests"]
+ plan_effect
+ channel_effect
+ platform_effect
+ noise
)
probability = 1 / (
1 + np.exp(-raw_score)
)
target = rng.binomial(
n=1,
p=probability,
)
categorical_features = [
"plan",
"platform",
"acquisition_channel",
"industry",
"campaign_group",
]
for column in categorical_features:
data[column] = (
data[column]
.fillna("__MISSING__")
.astype(str)
)
return (
data,
pd.Series(
target,
name="target",
),
categorical_features,
)
ایجاد و بررسی داده:
(
X,
y,
categorical_features,
) = create_dataset()
print(X.head())
print(X.dtypes)
print("\nDataset shape:")
print(X.shape)
print("\nTarget distribution:")
print(y.value_counts())
print("\nTarget ratio:")
print(
y.value_counts(
normalize=True
)
)
نکته مهم درباره ستونهای دستهای
مقادیر Categorical در CatBoost بهتر است بهصورت String یا Integer مشخص و سازگار باشند.
برای جایگزینکردن مقدارهای گمشده:
for column in categorical_features:
X[column] = (
X[column]
.fillna("__MISSING__")
.astype(str)
)
بهتر است مقدار گمشده را به یک Category مشخص تبدیل کنید. این کار باعث میشود رفتار Train و Production قابلکنترلتر باشد.
برای داده عددی میتوانید از روشهایی مانند Median استفاده کنید:
numeric_columns = [
column
for column in X.columns
if column
not in categorical_features
]
numeric_medians = (
X[numeric_columns]
.median()
.to_dict()
)
X[numeric_columns] = (
X[numeric_columns]
.fillna(numeric_medians)
)
Medianهای زمان آموزش باید برای زمان پیشبینی نیز ذخیره شوند.
تقسیم Train، Validation و Test
ابتدا ۲۰ درصد داده را برای Test کنار میگذاریم:
(
X_train_valid,
X_test,
y_train_valid,
y_test,
) = train_test_split(
X,
y,
test_size=0.20,
stratify=y,
random_state=RANDOM_STATE,
)
سپس Validation را جدا میکنیم:
(
X_train,
X_valid,
y_train,
y_valid,
) = train_test_split(
X_train_valid,
y_train_valid,
test_size=0.20,
stratify=y_train_valid,
random_state=RANDOM_STATE,
)
اندازه مجموعهها:
print(
"Train:",
X_train.shape,
)
print(
"Validation:",
X_valid.shape,
)
print(
"Test:",
X_test.shape,
)
در این تقسیمبندی:
- ۶۴ درصد کل داده برای Train
- ۱۶ درصد برای Validation
- ۲۰ درصد برای Test
مجموعه Test نباید برای انتخاب پارامترها، Early Stopping یا Threshold استفاده شود.
ساخت Pool در CatBoost
کلاس Pool داده، Target و مشخصات ویژگیها را در یک ساختار قرار میدهد:
train_pool = Pool(
data=X_train,
label=y_train,
cat_features=categorical_features,
feature_names=list(
X_train.columns
),
)
valid_pool = Pool(
data=X_valid,
label=y_valid,
cat_features=categorical_features,
feature_names=list(
X_valid.columns
),
)
test_pool = Pool(
data=X_test,
label=y_test,
cat_features=categorical_features,
feature_names=list(
X_test.columns
),
)
میتوان cat_features را با نام ستون یا Index ستونها مشخص کرد. استفاده از نام ستونها معمولاً خوانایی و قابلیت نگهداری بهتری دارد.
نمونههای رسمی ساخت Pool با دادههای عددی و دستهای در راهنمای استفاده CatBoost ارائه شدهاند.
ساخت مدل CatBoostClassifier
model = CatBoostClassifier(
iterations=2000,
learning_rate=0.035,
depth=7,
loss_function="Logloss",
eval_metric="AUC",
auto_class_weights="Balanced",
l2_leaf_reg=5.0,
random_strength=1.0,
random_seed=RANDOM_STATE,
early_stopping_rounds=60,
use_best_model=True,
allow_writing_files=False,
verbose=False,
thread_count=-1,
)
معنی پارامترهای مهم
| پارامتر | کاربرد |
|---|---|
iterations | حداکثر تعداد درختها |
learning_rate | میزان اثر هر درخت جدید |
depth | عمق درختها |
loss_function | تابع خطای آموزش |
eval_metric | معیار انتخاب بهترین Iteration |
auto_class_weights | وزندهی خودکار به کلاسها |
l2_leaf_reg | Regularization نوع L2 |
random_strength | میزان تصادفیسازی هنگام انتخاب Split |
random_seed | Seed برای بازتولید نتیجه |
early_stopping_rounds | توقف آموزش پس از بهبودنیافتن |
use_best_model | نگهداری بهترین Iteration |
allow_writing_files | جلوگیری از ساخت فایلهای جانبی |
thread_count | تعداد Threadهای CPU |
از auto_class_weights و class_weights بهصورت همزمان استفاده نکنید.
اگر کلاسها تقریباً متعادل هستند، میتوانید وزندهی خودکار را حذف کنید و عملکرد هر دو حالت را مقایسه کنید.
آموزش مدل با Early Stopping
model.fit(
train_pool,
eval_set=valid_pool,
verbose=100,
)
نمایش بهترین Iteration:
print(
"Best iteration:",
model.get_best_iteration(),
)
print(
"Best score:",
model.get_best_score(),
)
CatBoost دارای Overfitting Detector است و میتواند آموزش را قبل از رسیدن به حداکثر تعداد درختها متوقف کند. early_stopping_rounds آموزش را زمانی متوقف میکند که معیار Validation برای تعداد مشخصی Iteration بهتر نشود. جزئیات این قابلیت در مستندات Overfitting Detection آمده است.
دریافت احتمال پیشبینی
احتمال کلاس مثبت روی Validation:
valid_probabilities = (
model.predict_proba(
valid_pool
)[:, 1]
)
تبدیل احتمال به کلاس با Threshold پیشفرض:
valid_predictions = (
valid_probabilities >= 0.50
).astype(int)
ارزیابی مدل CatBoost
print(
"Accuracy:",
accuracy_score(
y_valid,
valid_predictions,
),
)
print(
"Precision:",
precision_score(
y_valid,
valid_predictions,
),
)
print(
"Recall:",
recall_score(
y_valid,
valid_predictions,
),
)
print(
"F1:",
f1_score(
y_valid,
valid_predictions,
),
)
print(
"ROC-AUC:",
roc_auc_score(
y_valid,
valid_probabilities,
),
)
print(
"Average Precision:",
average_precision_score(
y_valid,
valid_probabilities,
),
)
معیارهای مهم طبقهبندی
| معیار | مفهوم |
|---|---|
| Accuracy | سهم کل پیشبینیهای درست |
| Precision | سهم پیشبینیهای مثبت که واقعاً مثبت هستند |
| Recall | سهم نمونههای مثبت که مدل پیدا کرده است |
| F1-score | تعادل Precision و Recall |
| ROC-AUC | کیفیت رتبهبندی دو کلاس |
| Average Precision | خلاصه منحنی Precision-Recall |
| Log Loss | کیفیت احتمالات پیشبینیشده |
برای داده نامتوازن، Accuracy بهتنهایی کافی نیست.
انتخاب Threshold مناسب
Threshold پیشفرض 0.5 همیشه بهترین انتخاب نیست. برای انتخاب Threshold بر اساس F1:
thresholds = np.arange(
0.10,
0.91,
0.01,
)
f1_scores = []
for threshold in thresholds:
predictions = (
valid_probabilities >= threshold
).astype(int)
score = f1_score(
y_valid,
predictions,
)
f1_scores.append(score)
best_index = int(
np.argmax(f1_scores)
)
best_threshold = float(
thresholds[best_index]
)
best_validation_f1 = float(
f1_scores[best_index]
)
print(
"Best threshold:",
best_threshold,
)
print(
"Best validation F1:",
best_validation_f1,
)
رسم نمودار:
plt.figure(
figsize=(9, 5)
)
plt.plot(
thresholds,
f1_scores,
)
plt.axvline(
best_threshold,
color="red",
linestyle="--",
label=(
f"Best threshold = "
f"{best_threshold:.2f}"
),
)
plt.xlabel("Threshold")
plt.ylabel("F1-score")
plt.title(
"Validation F1 by Threshold"
)
plt.legend()
plt.tight_layout()
plt.show()
اگر هزینه False Positive و False Negative متفاوت است، Threshold باید با توجه به هدف واقعی پروژه انتخاب شود.
ارزیابی نهایی روی Test
test_probabilities = (
model.predict_proba(
test_pool
)[:, 1]
)
test_predictions = (
test_probabilities
>= best_threshold
).astype(int)
محاسبه معیارها:
print(
"Test Accuracy:",
accuracy_score(
y_test,
test_predictions,
),
)
print(
"Test Precision:",
precision_score(
y_test,
test_predictions,
),
)
print(
"Test Recall:",
recall_score(
y_test,
test_predictions,
),
)
print(
"Test F1:",
f1_score(
y_test,
test_predictions,
),
)
print(
"Test ROC-AUC:",
roc_auc_score(
y_test,
test_probabilities,
),
)
print(
"Test Average Precision:",
average_precision_score(
y_test,
test_probabilities,
),
)
گزارش کامل:
print(
classification_report(
y_test,
test_predictions,
)
)
Confusion Matrix:
matrix = confusion_matrix(
y_test,
test_predictions,
)
print(matrix)
ساختار ماتریس:
[[True Negative, False Positive],
[False Negative, True Positive]]
رسم Confusion Matrix
from sklearn.metrics import (
ConfusionMatrixDisplay,
)
display = ConfusionMatrixDisplay(
confusion_matrix=matrix,
display_labels=[0, 1],
)
display.plot(
cmap="Purples",
)
plt.title(
"CatBoost Confusion Matrix"
)
plt.tight_layout()
plt.show()
بررسی روند آموزش
نتایج معیارها را دریافت کنید:
evaluation_results = (
model.get_evals_result()
)
print(
evaluation_results.keys()
)
معمولاً کلیدهای learn و validation یا نام مشابهی وجود دارند.
رسم AUC:
validation_scores = (
evaluation_results[
"validation"
]["AUC"]
)
best_iteration = (
model.get_best_iteration()
)
plt.figure(
figsize=(9, 5)
)
plt.plot(
validation_scores
)
plt.axvline(
best_iteration,
color="red",
linestyle="--",
label="Best iteration",
)
plt.xlabel(
"Iteration"
)
plt.ylabel(
"Validation AUC"
)
plt.title(
"CatBoost Validation AUC"
)
plt.legend()
plt.tight_layout()
plt.show()
اگر نام مجموعه Validation در خروجی متفاوت بود، کلیدهای دیکشنری را با print(evaluation_results.keys()) بررسی کنید.
محاسبه Feature Importance
feature_importance = (
model.get_feature_importance(
train_pool,
type="FeatureImportance",
)
)
importance_df = pd.DataFrame(
{
"feature": (
model.feature_names_
),
"importance": (
feature_importance
),
}
).sort_values(
"importance",
ascending=False,
)
print(
importance_df
)
رسم نمودار:
plot_data = (
importance_df
.head(15)
.sort_values(
"importance",
ascending=True,
)
)
plt.figure(
figsize=(9, 6)
)
plt.barh(
plot_data["feature"],
plot_data["importance"],
)
plt.xlabel(
"Feature importance"
)
plt.ylabel(
"Feature"
)
plt.title(
"CatBoost Feature Importance"
)
plt.tight_layout()
plt.show()
Feature Importance مشخص میکند مدل بیشتر از کدام ویژگیها استفاده کرده است؛ اما علت و معلول را اثبات نمیکند.
محاسبه SHAP Values در CatBoost
CatBoost میتواند SHAP Values را مستقیماً محاسبه کند:
sample_pool = Pool(
data=X_valid.head(200),
label=y_valid.head(200),
cat_features=(
categorical_features
),
feature_names=list(
X_valid.columns
),
)
shap_values = (
model.get_feature_importance(
sample_pool,
type="ShapValues",
)
)
print(
shap_values.shape
)
خروجی دارای یک ستون اضافه برای Expected Value است:
feature_shap_values = (
shap_values[:, :-1]
)
expected_values = (
shap_values[:, -1]
)
میانگین قدرمطلق SHAP برای هر ویژگی:
mean_absolute_shap = (
np.abs(
feature_shap_values
).mean(axis=0)
)
shap_importance_df = (
pd.DataFrame(
{
"feature": (
model.feature_names_
),
"mean_abs_shap": (
mean_absolute_shap
),
}
)
.sort_values(
"mean_abs_shap",
ascending=False,
)
)
print(
shap_importance_df
)
مستندات CatBoost، ShapValues را یکی از حالتهای متد get_feature_importance معرفی میکند. جزئیات آن در راهنمای Feature Importance و SHAP قابل مشاهده است.
SHAP توضیح میدهد هر ویژگی چگونه خروجی مدل را جابهجا کرده است، اما همچنان نباید آن را اثبات رابطه علت و معلولی در نظر گرفت.
تنظیم پارامترهای CatBoost
پارامتر depth
عمق بیشتر، ظرفیت مدل را افزایش میدهد؛ اما زمان آموزش و خطر Overfitting نیز بیشتر میشود.
مقادیر رایج برای آزمایش:
4
6
7
8
10
پارامتر learning_rate
مقادیر رایج:
0.01
0.03
0.05
0.10
نرخ یادگیری کمتر معمولاً به iterations بیشتری نیاز دارد.
پارامتر iterations
این پارامتر حداکثر تعداد درختها را مشخص میکند. هنگام استفاده از Early Stopping میتوانید مقدار نسبتاً بزرگی مانند ۱۰۰۰ یا ۲۰۰۰ انتخاب کنید.
پارامتر l2_leaf_reg
Regularization نوع L2 را کنترل میکند:
1
3
5
10
20
مقدار مناسب باید با Validation انتخاب شود.
پارامتر random_strength
این پارامتر میزان تصادفیسازی هنگام امتیازدهی به Splitها را کنترل میکند. افزایش آن ممکن است Overfitting را کاهش دهد، اما مقدار بیشازحد میتواند کیفیت مدل را پایین بیاورد.
پارامتر bagging_temperature
در Bootstrap نوع Bayesian، این پارامتر شدت Sampling را کنترل میکند:
bootstrap_type="Bayesian"
bagging_temperature=1.0
مقدار صفر به وزنهای تقریباً یکسان نزدیک است و مقدار بیشتر، Sampling تصادفیتری ایجاد میکند.
Randomized Search برای CatBoost
برای جستوجوی اولیه میتوان از RandomizedSearchCV استفاده کرد:
from sklearn.model_selection import (
RandomizedSearchCV,
)
search_model = CatBoostClassifier(
loss_function="Logloss",
eval_metric="AUC",
auto_class_weights="Balanced",
random_seed=RANDOM_STATE,
allow_writing_files=False,
verbose=False,
thread_count=1,
)
parameter_distributions = {
"iterations": [
250,
500,
800,
],
"learning_rate": [
0.02,
0.05,
0.10,
],
"depth": [
4,
6,
8,
10,
],
"l2_leaf_reg": [
1,
3,
5,
10,
],
"random_strength": [
0.5,
1.0,
2.0,
],
}
search = RandomizedSearchCV(
estimator=search_model,
param_distributions=(
parameter_distributions
),
n_iter=20,
scoring="average_precision",
cv=5,
random_state=RANDOM_STATE,
n_jobs=-1,
verbose=1,
)
search.fit(
X_train_valid,
y_train_valid,
cat_features=(
categorical_features
),
)
print(
"Best parameters:"
)
print(
search.best_params_
)
print(
"Best CV score:",
search.best_score_,
)
در این ساختار، thread_count=1 قرار داده شده تا اجرای موازی RandomizedSearchCV و پردازش داخلی CatBoost باعث مصرف کنترلنشده CPU نشوند.
بعد از انتخاب پارامترها، مدل نهایی را دوباره با Train و Validation آموزش دهید و Early Stopping را فعال کنید.
ذخیره مدل CatBoost
ایجاد پوشه:
artifacts_dir = Path(
"artifacts"
)
artifacts_dir.mkdir(
parents=True,
exist_ok=True,
)
ذخیره مدل در فرمت Native:
model.save_model(
artifacts_dir
/ "catboost_model.cbm",
format="cbm",
)
فرمت cbm فرمت Native مدل CatBoost و انتخاب مناسبی برای بارگذاری مجدد در Python است. متد و فرمتهای قابلاستفاده در مستندات رسمی save_model توضیح داده شدهاند.
ذخیره Metadata
numeric_columns = [
column
for column in X.columns
if column
not in categorical_features
]
metadata = {
"threshold": (
best_threshold
),
"feature_names": list(
X.columns
),
"categorical_features": (
categorical_features
),
"numeric_features": (
numeric_columns
),
"missing_category": (
"__MISSING__"
),
"best_iteration": int(
model.get_best_iteration()
),
"target_name": (
"completed_onboarding"
),
}
with (
artifacts_dir
/ "metadata.json"
).open(
"w",
encoding="utf-8",
) as file:
json.dump(
metadata,
file,
ensure_ascii=False,
indent=2,
)
همراه مدل بهتر است موارد زیر نیز ثبت شوند:
- نسخه CatBoost
- نسخه Python
- نسخه دیتاست
- زمان آموزش
- پارامترهای مدل
- نام و ترتیب ویژگیها
- نوع هر ستون
- سیاست Missing Value
- Threshold
- معیارهای Validation
- معیارهای Test
- شناسه نسخه مدل
بارگذاری مدل
فایل predict.py:
from pathlib import Path
import json
import pandas as pd
from catboost import (
CatBoostClassifier,
Pool,
)
artifacts_dir = Path(
"artifacts"
)
model = CatBoostClassifier()
model.load_model(
artifacts_dir
/ "catboost_model.cbm"
)
with (
artifacts_dir
/ "metadata.json"
).open(
"r",
encoding="utf-8",
) as file:
metadata = json.load(file)
متد load_model برای بارگذاری مدل ذخیرهشده استفاده میشود و فرمت پیشفرض آن cbm است. جزئیات در مستندات رسمی load_model موجود است.
پیشبینی روی رکورد جدید
new_record = {
"monthly_sessions": 16,
"days_since_signup": 12,
"used_features": 9,
"average_session_minutes": 13.5,
"help_page_visits": 2,
"support_requests": 1,
"plan": "pro",
"platform": "web",
"acquisition_channel": "organic",
"industry": "software",
"campaign_group": "campaign_04",
}
input_df = pd.DataFrame(
[new_record]
)
اعتبارسنجی ویژگیها:
feature_names = (
metadata["feature_names"]
)
missing_features = (
set(feature_names)
- set(input_df.columns)
)
unexpected_features = (
set(input_df.columns)
- set(feature_names)
)
if missing_features:
raise ValueError(
"Missing features: "
f"{sorted(missing_features)}"
)
if unexpected_features:
raise ValueError(
"Unexpected features: "
f"{sorted(unexpected_features)}"
)
input_df = input_df[
feature_names
]
تبدیل Categoryها به String:
for column in (
metadata[
"categorical_features"
]
):
input_df[column] = (
input_df[column]
.fillna(
metadata[
"missing_category"
]
)
.astype(str)
)
ساخت Pool و پیشبینی:
input_pool = Pool(
data=input_df,
cat_features=(
metadata[
"categorical_features"
]
),
feature_names=(
feature_names
),
)
probability = float(
model.predict_proba(
input_pool
)[0, 1]
)
threshold = float(
metadata["threshold"]
)
predicted_class = int(
probability >= threshold
)
result = {
"probability": round(
probability,
6,
),
"threshold": threshold,
"predicted_class": (
predicted_class
),
}
print(result)
CatBoost میتواند Categoryهایی را که در Train مشاهده نشدهاند پردازش کند، اما افزایش Categoryهای ناشناخته میتواند نشانه Data Drift باشد و باید پایش شود.
ساخت تابع پیشبینی قابلاستفاده
def predict_record(
model: CatBoostClassifier,
record: dict,
metadata: dict,
) -> dict:
feature_names = (
metadata["feature_names"]
)
missing_features = (
set(feature_names)
- set(record.keys())
)
if missing_features:
raise ValueError(
"Missing features: "
f"{sorted(missing_features)}"
)
input_df = pd.DataFrame(
[record]
)
input_df = input_df[
feature_names
]
for column in (
metadata[
"categorical_features"
]
):
input_df[column] = (
input_df[column]
.fillna(
metadata[
"missing_category"
]
)
.astype(str)
)
input_pool = Pool(
input_df,
cat_features=(
metadata[
"categorical_features"
]
),
feature_names=(
feature_names
),
)
probability = float(
model.predict_proba(
input_pool
)[0, 1]
)
threshold = float(
metadata["threshold"]
)
return {
"probability": round(
probability,
6,
),
"threshold": threshold,
"predicted_class": int(
probability >= threshold
),
}
استفاده:
prediction = predict_record(
model=model,
record=new_record,
metadata=metadata,
)
print(prediction)
استفاده از GPU در CatBoost
اگر نسخه نصبشده و سیستم شما از GPU پشتیبانی میکنند:
gpu_model = CatBoostClassifier(
iterations=1500,
learning_rate=0.04,
depth=7,
loss_function="Logloss",
eval_metric="AUC",
task_type="GPU",
devices="0",
random_seed=42,
early_stopping_rounds=50,
allow_writing_files=False,
verbose=100,
)
آموزش:
gpu_model.fit(
train_pool,
eval_set=valid_pool,
)
استفاده از GPU برای دیتاست کوچک همیشه سریعتر نیست. زمان انتقال داده و آمادهسازی GPU نیز باید در Benchmark لحاظ شود.
ترکیب CatBoost با مدلهای زبانی
CatBoost و مدل زبانی نقشهای متفاوتی دارند:
- CatBoost داده جدولی را تحلیل میکند.
- مدل زبانی متن را پردازش یا تولید میکند.
- CatBoost احتمال، کلاس یا مقدار عددی تولید میکند.
- مدل زبانی میتواند نتیجه را توضیح دهد.
- منطق نهایی برنامه باید در Backend باقی بماند.
یک Pipeline ترکیبی:
متن کاربر
↓
استخراج داده ساختاریافته با مدل زبانی
↓
اعتبارسنجی JSON
↓
ساخت Featureهای CatBoost
↓
پیشبینی احتمال یا کلاس
↓
تولید توضیح قابلفهم با مدل زبانی
نباید مقدار خروجی CatBoost را برای «بهتر بهنظررسیدن پاسخ» به مدل زبانی سپرد. مقدار عددی باید بدون تغییر وارد گزارش شود.
توضیح نتیجه CatBoost با API درواره
برای استفاده از مدلهای زبانی در کنار CatBoost میتوانید از API هوش مصنوعی درواره استفاده کنید.
تنظیم متغیرهای محیطی در Linux و macOS:
export DARVAREH_API_KEY="YOUR_DARVAREH_API_KEY"
export DARVAREH_MODEL_ID="YOUR_MODEL_ID"
در Windows PowerShell:
$env:DARVAREH_API_KEY="YOUR_DARVAREH_API_KEY"
$env:DARVAREH_MODEL_ID="YOUR_MODEL_ID"
ارسال نتیجه:
import os
import requests
api_key = os.environ[
"DARVAREH_API_KEY"
]
model_id = os.environ[
"DARVAREH_MODEL_ID"
]
prediction_result = {
"probability": 0.68,
"threshold": 0.54,
"predicted_class": 1,
}
response = requests.post(
"https://api.darvareh.ir/v1/chat/completions",
headers={
"Authorization": (
f"Bearer {api_key}"
),
"Content-Type": (
"application/json"
),
},
json={
"model": model_id,
"messages": [
{
"role": "system",
"content": (
"خروجی مدل یادگیری "
"ماشین را دقیق و بدون "
"تغییر اعداد توضیح بده. "
"هیچ علت یا اطلاعات "
"جدیدی اختراع نکن."
),
},
{
"role": "user",
"content": f"""
نتیجه مدل CatBoost:
{prediction_result}
در حداکثر سه جمله توضیح بده:
1. احتمال مدل چقدر است؟
2. چرا کلاس نهایی یک شده است؟
3. تأکید کن که نتیجه قطعی نیست.
""",
},
],
"temperature": 0.2,
},
timeout=60,
)
response.raise_for_status()
data = response.json()
explanation = data[
"choices"
][0]["message"]["content"]
print(explanation)
مدل مناسب و Model ID آن را از صفحه مدلها و قیمتهای درواره انتخاب کنید.
کلید API را در Frontend، کد عمومی یا مخزن Git قرار ندهید. درخواست باید از Backend ارسال شود.
آمادهسازی CatBoost برای Production
پیش از استقرار مدل این موارد را بررسی کنید:
- مدل هنگام شروع برنامه یکبار بارگذاری میشود.
- نام و ترتیب Featureها ثابت است.
- نوع تمام ستونها بررسی میشود.
- Categoryهای گمشده با یک سیاست ثابت مدیریت میشوند.
- Median یا سایر مقادیر Preprocessing ذخیره شدهاند.
- Threshold همراه مدل نگهداری میشود.
- نسخه مدل در خروجی داخلی ثبت میشود.
- Latency پیشبینی اندازهگیری شده است.
- Test مستقل استفاده شده است.
- Data Drift پایش میشود.
- نرخ Categoryهای جدید ثبت میشود.
- Logها فاقد اطلاعات شخصی و حساس هستند.
- امکان بازگشت به مدل قبلی وجود دارد.
- عملکرد مدل بعد از استقرار ارزیابی میشود.
خطاهای رایج CatBoost
خطای No module named 'catboost'
python -m pip install catboost
بررسی نصب:
python -m pip show catboost
خطای مربوط به cat_features
مطمئن شوید نام ویژگیهای دستهای دقیقاً با ستونهای DataFrame یکسان است:
print(
X.columns.tolist()
)
print(
categorical_features
)
خطای مربوط به مقدار NaN در Category
مقادیر گمشده را به یک String ثابت تبدیل کنید:
X[column] = (
X[column]
.fillna("__MISSING__")
.astype(str)
)
خطای ناسازگاری Featureها هنگام Predict
ترتیب و نام ستونها باید با زمان آموزش سازگار باشد:
input_df = input_df[
feature_names
]
مدل Overfit میشود
راهکارهای قابل آزمایش:
- کاهش
depth - کاهش
learning_rate - افزایش
l2_leaf_reg - استفاده از Early Stopping
- کاهش Featureهای نویزی
- افزایش داده باکیفیت
- بررسی Data Leakage
- ساخت Split زمانی در دادههای وابسته به زمان
Probabilityها بیشازحد بالا یا پایین هستند
اگر از auto_class_weights یا class_weights استفاده کردهاید، Calibration احتمال را بررسی کنید. علاوه بر ROC-AUC و F1، Log Loss و Reliability Curve نیز مفید هستند.
آموزش روی CPU کند است
- تعداد
iterationsرا برای آزمایش اولیه کاهش دهید. - Early Stopping را فعال کنید.
thread_count=-1را بررسی کنید.- Featureهای غیرضروری را حذف کنید.
- زمان آموزش CPU و GPU را Benchmark کنید.
- جستوجوی Hyperparameter را محدود و مرحلهای انجام دهید.
اشتباهات رایج در پروژه CatBoost
One-hot Encoding تمام Categoryها قبل از CatBoost
این کار یکی از مزیتهای اصلی CatBoost را از بین میبرد و ممکن است تعداد ویژگیها را بسیار افزایش دهد.
استفاده از Test برای Early Stopping
Test باید فقط برای ارزیابی نهایی استفاده شود.
انتخاب Threshold روی Test
Threshold باید روی Validation انتخاب شود.
گزارشکردن فقط Accuracy
Accuracy در داده نامتوازن ممکن است گمراهکننده باشد.
نادیدهگرفتن Categoryهای جدید
Category جدید معمولاً مانع اجرای CatBoost نمیشود؛ اما افزایش آن میتواند نشانه تغییر رفتار داده باشد.
تفسیر SHAP بهعنوان رابطه علت و معلولی
SHAP رفتار مدل را توضیح میدهد، نه واقعیت قطعی جهان بیرونی را.
ذخیره مدل بدون Feature Schema
مدل بدون نام، ترتیب و نوع ویژگیها قابلاعتماد نیست.
استفاده از خروجی مدل بهعنوان تصمیم قطعی
مدل یادگیری ماشین احتمال یا الگوی آماری تولید میکند. نحوه استفاده از نتیجه باید با منطق برنامه، کیفیت داده و بررسی انسانی متناسب باشد.
چکلیست نهایی CatBoost
- مسئله و Target روشن است.
- دادههای Train، Validation و Test جدا هستند.
- Data Leakage بررسی شده است.
- Categorical Features مشخص شدهاند.
- Missing Valueها مدیریت شدهاند.
- Baseline ساده ساخته شده است.
- Early Stopping فعال است.
- چند معیار ارزیابی گزارش شده است.
- Threshold روی Validation انتخاب شده است.
- Test فقط یکبار برای ارزیابی نهایی استفاده شده است.
- Feature Importance با احتیاط تفسیر میشود.
- مدل در فرمت
cbmذخیره شده است. - Metadata و Feature Schema ذخیره شدهاند.
- ورودی Production اعتبارسنجی میشود.
- Drift و Categoryهای جدید پایش میشوند.
سؤالات متداول
CatBoost چیست؟
CatBoost یک کتابخانه Gradient Boosting مبتنی بر درخت تصمیم است که تمرکز ویژهای بر پردازش مستقیم ویژگیهای دستهای دارد.
آیا CatBoost به One-hot Encoding نیاز دارد؟
معمولاً خیر. CatBoost میتواند ویژگیهای دستهای را مستقیماً دریافت کند و مستندات رسمی نیز انجام One-hot Encoding دستی را توصیه نمیکنند.
CatBoost بهتر است یا XGBoost؟
پاسخ به دیتاست بستگی دارد. CatBoost برای دادههای دارای Category زیاد گزینه مهمی است. XGBoost نیز روی طیف وسیعی از دادههای جدولی عملکرد قدرتمندی دارد.
CatBoost بهتر است یا LightGBM؟
LightGBM معمولاً برای سرعت بالا روی دادههای بزرگ شناخته میشود. CatBoost میتواند Workflow دادههای دستهای را سادهتر کند. هر دو باید روی Test مستقل مقایسه شوند.
آیا CatBoost برای متن فارسی مناسب است؟
CatBoost از ویژگیهای متنی پشتیبانی میکند، اما برای مسائل پیچیده زبان فارسی معمولاً استفاده از TF-IDF، Embedding یا مدل زبانی و سپس ترکیب آن با CatBoost انعطاف بیشتری دارد.
آیا CatBoost به StandardScaler نیاز دارد؟
مدلهای درختی CatBoost معمولاً به StandardScaler نیاز ندارند. پاکسازی داده و مدیریت صحیح نوع ستونها همچنان ضروری است.
آیا CatBoost از GPU پشتیبانی میکند؟
بله. با تنظیم task_type="GPU" میتوان از GPU سازگار استفاده کرد. سرعت واقعی باید روی دیتاست پروژه اندازهگیری شود.
فرمت مناسب ذخیره مدل چیست؟
برای بارگذاری مجدد در CatBoost، فرمت Native با پسوند .cbm گزینه مناسبی است.
آیا CatBoost Category جدید را میپذیرد؟
CatBoost میتواند با مقادیر دستهای جدید کار کند، اما افزایش Categoryهای دیدهنشده ممکن است کیفیت پیشبینی را کاهش دهد و باید بهعنوان بخشی از Data Drift پایش شود.
آیا CatBoost برای دادههای کوچک مناسب است؟
قابلاستفاده است، اما احتمال Overfitting بیشتر میشود. در این شرایط باید مدلهای سادهتر، Cross-validation و Regularization را نیز بررسی کنید.
آیا میتوان CatBoost را داخل API استفاده کرد؟
بله. میتوانید مدل ذخیرهشده را در FastAPI، Flask یا Django بارگذاری و یک Endpoint برای Predict ایجاد کنید.
آیا میتوان CatBoost را به درواره متصل کرد؟
بله. CatBoost میتواند احتمال یا کلاس را محاسبه کند و مدل زبانی از طریق API درواره میتواند نتیجه را خلاصه یا به زبان طبیعی توضیح دهد.
جمعبندی
CatBoost یکی از بهترین گزینهها برای ساخت مدل یادگیری ماشین روی دادههای جدولی دارای ستونهای دستهای است. پشتیبانی مستقیم از Categorical Features، Ordered Boosting، Early Stopping، Feature Importance، SHAP و امکان آموزش روی CPU و GPU، این کتابخانه را به ابزاری کاربردی برای توسعهدهندگان و متخصصان داده تبدیل کرده است.
بااینحال، انتخاب CatBoost بهتنهایی موفقیت پروژه را تضمین نمیکند. کیفیت داده، تقسیم درست Train و Test، جلوگیری از Data Leakage، انتخاب Threshold، اعتبارسنجی ورودی و پایش Drift اهمیت بیشتری از انتخاب یک نام مشهور برای الگوریتم دارند.
در پروژه واقعی، ابتدا یک Baseline ساده بسازید؛ سپس CatBoost را با XGBoost، LightGBM و Random Forest مقایسه کنید. مدلی را انتخاب کنید که علاوه بر معیارهای مناسب Test، از نظر Latency، حجم، هزینه و نگهداری نیز با نیاز Production سازگار باشد.
برای افزودن قابلیتهای مدلهای زبانی به نرمافزارهای Python و Pipelineهای یادگیری ماشین میتوانید از API هوش مصنوعی درواره استفاده کنید. برای مشاهده مدلهای قابلاستفاده و قیمت بهروز، صفحه مدلها و قیمتهای درواره را ببینید.
مقالات مرتبط
- آموزش هوش مصنوعی با پایتون و API درواره
- تحلیل فایل CSV با هوش مصنوعی
- راهنمای ارزیابی مدلهای هوش مصنوعی و Evals
- راهنمای مدلهای هوش مصنوعی
- آموزش Inference در هوش مصنوعی
- آموزش Structured Outputs و JSON Schema
- آموزش دریافت API Key هوش مصنوعی
برای مطالعه شرایط استفاده و محدودیتهای مسئولیت، صفحه «سلب مسئولیت» را مشاهده کنید.