XGBoost چیست؟ آموزش کامل ساخت مدل یادگیری ماشین با پایتون
آموزش کامل XGBoost با پایتون از مفاهیم پایه تا ساخت، ارزیابی، بهینهسازی و ذخیره یک مدل طبقهبندی واقعی؛ همراه با کد کامل، توضیح پارامترها، رفع خطا و اتصال به API درواره.
XGBoost یکی از محبوبترین و کاربردیترین کتابخانهها برای ساخت مدلهای یادگیری ماشین روی دادههای جدولی است. اگر اطلاعات شما بهشکل جدول، فایل CSV، دیتابیس، گزارش فروش، رفتار کاربران یا رکوردهای یک نرمافزار ذخیره شده باشد، XGBoost میتواند یکی از اولین گزینههایی باشد که برای طبقهبندی، پیشبینی و رتبهبندی آزمایش میکنید.
محبوبیت XGBoost فقط به دقت آن مربوط نیست. این کتابخانه امکاناتی مانند Regularization، پردازش مقادیر گمشده، Early Stopping، اجرای موازی، پشتیبانی از GPU و سازگاری با Scikit-learn را نیز در اختیار توسعهدهندگان قرار میدهد.
در این آموزش، ابتدا با ساختار XGBoost آشنا میشویم و سپس یک پروژه طبقهبندی را از صفر پیادهسازی میکنیم. کد پروژه شامل تولید داده آزمایشی، تقسیم صحیح دادهها، آموزش مدل، اندازهگیری معیارهای ارزیابی، انتخاب Threshold، تحلیل اهمیت ویژگیها و ذخیره مدل خواهد بود.
در بخش پایانی نیز میبینیم چگونه میتوان نتیجه یک مدل XGBoost را با استفاده از API درواره به گزارشی قابلفهم برای کاربر تبدیل کرد.
XGBoost چیست؟
نام XGBoost مخفف Extreme Gradient Boosting است. این کتابخانه پیادهسازی بهینهشدهای از الگوریتم Gradient Boosting ارائه میدهد و معمولاً از مجموعهای از درختهای تصمیم برای ساخت مدل نهایی استفاده میکند.
در مدلهای Boosting، درختها مستقل از یکدیگر ساخته نمیشوند. هر درخت جدید تلاش میکند بخشی از خطاهای درختهای قبلی را اصلاح کند. میتوان این سازوکار را بهصورت ساده چنین نمایش داد:
پیشبینی نهایی =
پیشبینی اولیه
+ نرخ یادگیری × خروجی درخت اول
+ نرخ یادگیری × خروجی درخت دوم
+ ...
+ نرخ یادگیری × خروجی درخت آخر
XGBoost علاوه بر کمینهکردن خطای پیشبینی، پیچیدگی مدل را نیز کنترل میکند:
Objective = Training Loss + Regularization
بخش Training Loss نشان میدهد پیشبینیهای مدل چقدر با مقادیر واقعی تفاوت دارند. بخش Regularization مدل را از ساخت درختهای بیشازحد پیچیده بازمیدارد و به کاهش Overfitting کمک میکند.
برای مطالعه ساختار ریاضی Boosted Trees میتوانید به توضیح رسمی XGBoost درباره درختهای Boosting مراجعه کنید.
XGBoost برای چه پروژههایی مناسب است؟
XGBoost بیشتر برای دادههای ساختاریافته و جدولی مناسب است. نمونه کاربردهای رایج آن عبارتاند از:
- پیشبینی احتمال انجام یک رویداد
- طبقهبندی درخواستها و رکوردها
- تشخیص الگو در رفتار کاربران
- پیشبینی تقاضا یا میزان استفاده
- امتیازدهی به سرنخهای فروش
- دستهبندی بازخوردها پس از استخراج ویژگی
- پیشبینی مقدار یک متغیر عددی
- رتبهبندی نتایج
- ساخت مدل پایه برای مقایسه با روشهای پیچیدهتر
این کتابخانه مستقیماً برای پردازش متن خام، تصویر، صدا یا ویدئو طراحی نشده است. برای این نوع دادهها معمولاً ابتدا Embedding یا ویژگیهای عددی استخراج میشود و سپس میتوان XGBoost را روی آن ویژگیها آموزش داد.
تفاوت XGBoost با Random Forest چیست؟
هر دو روش از چندین درخت تصمیم استفاده میکنند، اما شیوه ساخت درختها متفاوت است.
| ویژگی | XGBoost | Random Forest |
|---|---|---|
| شیوه آموزش | درختها معمولاً بهترتیب ساخته میشوند | درختها تا حد زیادی مستقل ساخته میشوند |
| هدف هر درخت | اصلاح خطاهای مدل قبلی | تولید یک پیشبینی مستقل |
| حساسیت به تنظیم پارامترها | بیشتر | کمتر |
| سرعت رسیدن به مدل پایه | متوسط | معمولاً سریع |
| کنترل Overfitting | با Regularization و پارامترهای متعدد | با میانگینگیری و تصادفیسازی |
| عملکرد روی داده جدولی | اغلب بسیار قوی | معمولاً پایدار و قابلاعتماد |
| نیاز به Feature Scaling | معمولاً ندارد | معمولاً ندارد |
بهتر است در یک پروژه واقعی هر دو مدل را آزمایش کنید. هیچ الگوریتمی روی تمام دیتاستها بهترین نتیجه را تضمین نمیکند.
پیشنیازهای آموزش
برای اجرای پروژه به Python 3 و کتابخانههای زیر نیاز داریم:
pip install xgboost scikit-learn pandas numpy matplotlib
برای بررسی نسخه نصبشده XGBoost اجرا کنید:
python -c "import xgboost; print(xgboost.__version__)"
بهتر است برای هر پروژه یک Virtual Environment مستقل بسازید:
python -m venv .venv
در ویندوز:
.venv\Scripts\activate
در Linux و macOS:
source .venv/bin/activate
سپس وابستگیها را داخل همان محیط نصب کنید.
ساختار پیشنهادی پروژه
ساختار ساده زیر برای شروع کافی است:
xgboost-project/
├── .venv/
├── artifacts/
├── train.py
├── predict.py
└── requirements.txt
محتوای فایل requirements.txt:
xgboost
scikit-learn
pandas
numpy
matplotlib
requests
برای نصب تمام وابستگیها:
pip install -r requirements.txt
پروژه عملی: ساخت مدل طبقهبندی با XGBoost
در این پروژه یک دیتاست مصنوعی میسازیم که یک مسئله طبقهبندی دودویی را شبیهسازی میکند. هدف، پیشبینی احتمال وقوع یک رویداد بر اساس ۲۰ ویژگی عددی است.
استفاده از داده مصنوعی باعث میشود مثال بدون دانلود فایل خارجی اجرا شود و هیچ داده شخصی یا حساس در پروژه وجود نداشته باشد. تابع make_classification در Scikit-learn برای تولید مسائل طبقهبندی کنترلشده طراحی شده است و میتواند ویژگیهای مفید، تکراری و نویزی ایجاد کند. جزئیات آن در مستندات رسمی Scikit-learn آمده است.
مرحله اول: Import کردن کتابخانهها
فایل train.py را بسازید:
from pathlib import Path
import json
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.datasets import make_classification
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
from xgboost import XGBClassifier
مرحله دوم: تولید دیتاست آزمایشی
در این مثال ۵۰۰۰ رکورد با ۲۰ ویژگی ایجاد میکنیم:
RANDOM_STATE = 42
X_array, y = make_classification(
n_samples=5000,
n_features=20,
n_informative=10,
n_redundant=5,
n_repeated=0,
n_classes=2,
weights=[0.85, 0.15],
class_sep=1.2,
flip_y=0.02,
random_state=RANDOM_STATE,
)
feature_names = [f"feature_{i:02d}" for i in range(X_array.shape[1])]
X = pd.DataFrame(
X_array,
columns=feature_names,
)
y = pd.Series(y, name="target")
print("X shape:", X.shape)
print("Class distribution:")
print(y.value_counts(normalize=True))
پارامتر weights=[0.85, 0.15] باعث میشود کلاس مثبت کمتر از کلاس منفی باشد. چنین شرایطی در پروژههای واقعی بسیار رایج است.
خروجی توزیع کلاسها تقریباً شبیه زیر خواهد بود:
0 0.85
1 0.15
در این شرایط، Accuracy بهتنهایی معیار مناسبی نیست. مدلی که همیشه کلاس صفر را پیشبینی کند، ممکن است Accuracy حدود ۸۵ درصد داشته باشد؛ درحالیکه هیچ نمونه مثبتی را شناسایی نکرده است.
تقسیم صحیح داده به Train، Validation و Test
یکی از مهمترین مراحل پروژه یادگیری ماشین، تقسیم دادهها است.
- مجموعه Train برای یادگیری پارامترهای مدل استفاده میشود.
- مجموعه Validation برای انتخاب پارامترها، Early Stopping و Threshold استفاده میشود.
- مجموعه 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)
استفاده از stratify کمک میکند نسبت کلاسها در هر سه مجموعه تقریباً حفظ شود.
یک اشتباه رایج این است که بارها عملکرد مدل را روی Test بررسی کنیم و بر اساس آن پارامترها را تغییر دهیم. در این حالت، مجموعه Test عملاً به بخشی از فرایند تنظیم مدل تبدیل میشود و دیگر ارزیابی مستقلی ارائه نمیکند.
آیا XGBoost به StandardScaler نیاز دارد؟
مدلهای درختی معمولاً به استانداردسازی ویژگیهای عددی نیاز ندارند. بنابراین برای یک دیتاست کاملاً عددی میتوانید XGBoost را بدون StandardScaler آموزش دهید.
بااینحال، اگر در Pipeline خود الگوریتمهای دیگری مانند Logistic Regression، KNN یا شبکه عصبی دارید، ممکن است Scaling برای آن بخشها ضروری باشد.
نبود نیاز عمومی به Scaling به این معنا نیست که کیفیت داده اهمیتی ندارد. همچنان باید موارد زیر را بررسی کنید:
- نوع داده هر ستون
- دادههای گمشده
- مقادیر غیرممکن
- ویژگیهای نشتکننده اطلاعات
- دادههای تکراری
- تفاوت ساختار داده آموزش و Production
- نحوه کدگذاری متغیرهای دستهای
محاسبه وزن کلاسها
برای دیتاست نامتوازن میتوان از پارامتر scale_pos_weight استفاده کرد. یک نقطه شروع رایج برای محاسبه آن، نسبت تعداد نمونههای منفی به مثبت در مجموعه Train است:
negative_count = int((y_train == 0).sum())
positive_count = int((y_train == 1).sum())
scale_pos_weight = negative_count / positive_count
print("Negative samples:", negative_count)
print("Positive samples:", positive_count)
print("scale_pos_weight:", scale_pos_weight)
این مقدار یک نقطه شروع است، نه یک قانون قطعی. باید اثر آن را روی Precision، Recall، F1 و هزینه واقعی خطاها بررسی کنید.
ساخت مدل XGBClassifier
مدل پایه را بهصورت زیر میسازیم:
model = XGBClassifier(
objective="binary:logistic",
eval_metric="aucpr",
n_estimators=1000,
learning_rate=0.05,
max_depth=4,
min_child_weight=2,
subsample=0.80,
colsample_bytree=0.80,
reg_alpha=0.0,
reg_lambda=1.0,
scale_pos_weight=scale_pos_weight,
tree_method="hist",
early_stopping_rounds=40,
random_state=RANDOM_STATE,
n_jobs=-1,
)
در نسخههای جدید رابط Scikit-learn در XGBoost، پارامترهایی مانند eval_metric و early_stopping_rounds باید در سازنده مدل قرار بگیرند، نه در متد fit. این تغییر در یادداشت انتشار رسمی XGBoost مستند شده است.
معنی مهمترین پارامترها
| پارامتر | کاربرد |
|---|---|
objective | نوع مسئله و تابع هدف |
eval_metric | معیار بررسی عملکرد روی Validation |
n_estimators | حداکثر تعداد درختها یا Boosting Roundها |
learning_rate | سهم هر درخت جدید در پیشبینی نهایی |
max_depth | حداکثر عمق هر درخت |
min_child_weight | محدودکردن تقسیمهای بیشازحد جزئی |
subsample | سهم رکوردهای استفادهشده در هر مرحله |
colsample_bytree | سهم ویژگیهای استفادهشده برای هر درخت |
reg_alpha | Regularization نوع L1 |
reg_lambda | Regularization نوع L2 |
scale_pos_weight | وزن بیشتر برای کلاس مثبت |
tree_method | الگوریتم ساخت درخت |
early_stopping_rounds | توقف در صورت بهبودنیافتن Validation |
n_jobs | تعداد Threadهای CPU |
فهرست کامل پارامترها در مستندات رسمی پارامترهای XGBoost موجود است.
آموزش مدل با Early Stopping
اکنون مدل را روی مجموعه Train آموزش میدهیم و Validation را برای Early Stopping در اختیار آن قرار میدهیم:
model.fit(
X_train,
y_train,
eval_set=[(X_valid, y_valid)],
verbose=False,
)
برای مشاهده بهترین Iteration:
print("Best iteration:", model.best_iteration)
print("Best score:", model.best_score)
اگر معیار Validation برای ۴۰ مرحله بهتر نشود، آموزش متوقف خواهد شد. به این ترتیب میتوان n_estimators را نسبتاً بزرگ انتخاب کرد و اجازه داد Early Stopping زمان مناسب توقف را مشخص کند.
XGBoost استفاده از Validation Set و Early Stopping را در راهنمای رسمی Python توضیح داده است.
مجموعه Test نباید برای Early Stopping استفاده شود؛ زیرا در این صورت اطلاعات مربوط به ارزیابی نهایی وارد فرایند آموزش خواهد شد.
ارزیابی مدل روی Validation
ابتدا احتمال کلاس مثبت را دریافت میکنیم:
valid_probabilities = model.predict_proba(X_valid)[:, 1]
valid_predictions = (valid_probabilities >= 0.50).astype(int)
سپس معیارها را محاسبه میکنیم:
print("Validation Accuracy:", accuracy_score(y_valid, valid_predictions))
print("Validation Precision:", precision_score(y_valid, valid_predictions))
print("Validation Recall:", recall_score(y_valid, valid_predictions))
print("Validation F1:", f1_score(y_valid, valid_predictions))
print("Validation ROC-AUC:", roc_auc_score(y_valid, valid_probabilities))
print(
"Validation Average Precision:",
average_precision_score(y_valid, valid_probabilities),
)
معنی معیارهای ارزیابی
| معیار | چه چیزی را اندازه میگیرد؟ |
|---|---|
| Accuracy | نسبت کل پیشبینیهای درست |
| Precision | چه سهمی از پیشبینیهای مثبت واقعاً مثبت بودهاند |
| Recall | چه سهمی از نمونههای مثبت شناسایی شدهاند |
| F1-score | تعادل میان Precision و Recall |
| ROC-AUC | توانایی کلی مدل در رتبهبندی دو کلاس |
| Average Precision | خلاصه عملکرد Precision-Recall در Thresholdهای مختلف |
در دادههای نامتوازن، Average Precision و منحنی Precision-Recall میتوانند تصویری کاربردیتر از Accuracy ارائه دهند. تعریف رسمی این معیار در مستندات Average Precision آمده است.
انتخاب Threshold مناسب
خروجی predict_proba یک احتمال بین صفر و یک است. Threshold پیشفرض معمولاً 0.5 است، اما لزوماً بهترین انتخاب نیست.
برای انتخاب Threshold بر اساس F1 روی Validation میتوانیم بنویسیم:
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)
میتوانید نمودار Threshold و F1 را نیز رسم کنید:
plt.figure(figsize=(9, 5))
plt.plot(thresholds, f1_scores)
plt.axvline(
best_threshold,
color="red",
linestyle="--",
label=f"Best threshold = {best_threshold:.2f}",
)
plt.xlabel("Threshold")
plt.ylabel("F1-score")
plt.title("Validation F1 by Threshold")
plt.legend()
plt.tight_layout()
plt.show()
Threshold باید بر اساس هدف پروژه انتخاب شود:
- اگر از دستدادن نمونههای مثبت پرهزینه است، Recall اهمیت بیشتری دارد.
- اگر هشدار اشتباه پرهزینه است، Precision اهمیت بیشتری پیدا میکند.
- اگر تعادل این دو مهم است، میتوان از F1 استفاده کرد.
- اگر هزینه هر نوع خطا مشخص است، بهتر است Threshold با یک تابع هزینه اختصاصی انتخاب شود.
Threshold را روی Test انتخاب نکنید. Test فقط باید پس از نهاییشدن مدل و Threshold استفاده شود.
ارزیابی نهایی روی مجموعه Test
پس از انتخاب Threshold روی Validation، مدل را یکبار روی Test ارزیابی میکنیم:
test_probabilities = model.predict_proba(X_test)[:, 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("\nClassification report:")
print(classification_report(y_test, test_predictions))
print("\nConfusion matrix:")
print(confusion_matrix(y_test, test_predictions))
Confusion Matrix برای مسئله دودویی ساختاری شبیه زیر دارد:
[[True Negative, False Positive],
[False Negative, True Positive]]
تنها مشاهده یک عدد مانند Accuracy برای تصمیمگیری درباره کیفیت مدل کافی نیست. گزارش ارزیابی باید حداقل شامل توزیع کلاسها، Confusion Matrix، Precision، Recall، F1 و یک معیار مستقل از Threshold باشد.
تحلیل اهمیت ویژگیها
برای بررسی اینکه کدام ویژگیها بیشتر در تصمیمهای درختها نقش داشتهاند، میتوان از Feature Importance استفاده کرد.
booster = model.get_booster()
importance_dict = booster.get_score(
importance_type="gain"
)
importance_df = (
pd.DataFrame(
importance_dict.items(),
columns=["feature", "gain"],
)
.sort_values("gain", ascending=False)
.reset_index(drop=True)
)
print(importance_df.head(10))
رسم نمودار:
top_features = importance_df.head(10).sort_values(
"gain",
ascending=True,
)
plt.figure(figsize=(9, 6))
plt.barh(
top_features["feature"],
top_features["gain"],
)
plt.xlabel("Average gain")
plt.ylabel("Feature")
plt.title("Top XGBoost Feature Importances")
plt.tight_layout()
plt.show()
انواع رایج Feature Importance در XGBoost عبارتاند از:
| نوع | مفهوم |
|---|---|
weight | تعداد دفعات استفاده از ویژگی برای Split |
gain | میانگین بهبود حاصل از Splitهای ویژگی |
cover | میانگین پوشش نمونهها در Splitهای ویژگی |
total_gain | مجموع Gain تمام Splitهای ویژگی |
total_cover | مجموع Coverage تمام Splitهای ویژگی |
اهمیت بالای یک ویژگی الزاماً به معنی رابطه علت و معلولی نیست. این عدد فقط نحوه استفاده مدل از داده را توصیف میکند. برای تحلیل دقیقتر میتوان از Permutation Importance یا SHAP استفاده کرد و نتیجه را همراه با دانش مسئله بررسی کرد.
تنظیم پارامترهای XGBoost
تنظیم تمام پارامترها بهصورت همزمان معمولاً باعث افزایش زمان پردازش و پیچیدگی تحلیل میشود. بهتر است مرحلهای عمل کنید.
پارامتر learning_rate
نرخ یادگیری مشخص میکند هر درخت جدید چه میزان روی پیشبینی نهایی اثر بگذارد.
- مقدار کمتر معمولاً به درختهای بیشتری نیاز دارد.
- مقدار زیاد ممکن است آموزش را سریعتر اما ناپایدارتر کند.
- مقادیر
0.03،0.05و0.1نقاط شروع رایجی هستند.
پارامتر max_depth
عمق بیشتر امکان یادگیری روابط پیچیدهتر را فراهم میکند، اما احتمال Overfitting را افزایش میدهد.
مقادیر ۳ تا ۸ معمولاً نقطه شروع قابلقبولی هستند، ولی مقدار مناسب به داده بستگی دارد.
پارامتر min_child_weight
افزایش این مقدار باعث محافظهکارترشدن مدل میشود و میتواند جلوی Splitهای مبتنی بر تعداد کمی نمونه را بگیرد.
پارامترهای subsample و colsample_bytree
این دو پارامتر بخشی از رکوردها و ویژگیها را برای ساخت درخت انتخاب میکنند. مقادیری مانند 0.7 تا 0.9 میتوانند به کاهش Overfitting کمک کنند.
پارامترهای reg_alpha و reg_lambda
این پارامترها Regularization مدل را کنترل میکنند:
reg_alphaمربوط به L1 است.reg_lambdaمربوط به L2 است.
افزایش Regularization میتواند مدل را سادهتر کند، اما مقدار بیشازحد نیز ممکن است باعث Underfitting شود.
جستوجوی پارامترها با RandomizedSearchCV
برای یک جستوجوی اولیه میتوان از RandomizedSearchCV استفاده کرد:
from sklearn.model_selection import RandomizedSearchCV
base_model = XGBClassifier(
objective="binary:logistic",
eval_metric="aucpr",
tree_method="hist",
scale_pos_weight=scale_pos_weight,
random_state=RANDOM_STATE,
n_jobs=-1,
)
parameter_distributions = {
"n_estimators": [150, 250, 400, 600],
"learning_rate": [0.02, 0.05, 0.1],
"max_depth": [3, 4, 5, 6, 8],
"min_child_weight": [1, 2, 5, 10],
"subsample": [0.70, 0.80, 0.90, 1.0],
"colsample_bytree": [0.70, 0.80, 0.90, 1.0],
"reg_alpha": [0.0, 0.01, 0.1, 1.0],
"reg_lambda": [0.5, 1.0, 2.0, 5.0],
}
search = RandomizedSearchCV(
estimator=base_model,
param_distributions=parameter_distributions,
n_iter=25,
scoring="average_precision",
cv=5,
random_state=RANDOM_STATE,
n_jobs=-1,
verbose=1,
)
search.fit(
X_train_valid,
y_train_valid,
)
print("Best parameters:")
print(search.best_params_)
print("Best cross-validation score:")
print(search.best_score_)
این مثال برای سادگی از Early Stopping داخل Cross-validation استفاده نمیکند. یک Workflow دقیقتر میتواند چنین باشد:
- با Cross-validation محدوده مناسب پارامترها را پیدا کنید.
- مدل منتخب را روی Train آموزش دهید.
- از Validation برای Early Stopping استفاده کنید.
- Threshold را روی Validation انتخاب کنید.
- فقط یکبار ارزیابی نهایی را روی Test انجام دهید.
جستوجوی بزرگتر همیشه نتیجه بهتر ایجاد نمیکند. طبق راهنمای رسمی تنظیم XGBoost، شناخت داده و Preprocessing مناسب میتواند از جستوجوی گسترده پارامترها مهمتر باشد.
کار با ستونهای دستهای
اگر DataFrame شما ستون دستهای دارد، میتوانید از پشتیبانی داخلی XGBoost استفاده کنید.
نمونه:
import pandas as pd
from xgboost import XGBClassifier
X = pd.DataFrame(
{
"plan": ["basic", "pro", "basic", "team"],
"region": ["north", "south", "west", "north"],
"usage_count": [12, 37, 9, 44],
}
)
y = pd.Series([0, 1, 0, 1])
X["plan"] = X["plan"].astype("category")
X["region"] = X["region"].astype("category")
categorical_model = XGBClassifier(
tree_method="hist",
enable_categorical=True,
n_estimators=100,
max_depth=3,
learning_rate=0.05,
eval_metric="logloss",
random_state=42,
)
categorical_model.fit(X, y)
هنگام استفاده از ویژگیهای دستهای باید مدل را با JSON یا UBJSON ذخیره کنید تا اطلاعات مربوط به نوع ویژگیها حفظ شود. این موضوع در مستندات رسمی دادههای دستهای XGBoost تأکید شده است.
در پروژه واقعی باید بررسی کنید که دستههای ورودی Production با دستههای زمان آموزش سازگار باشند. ورود یک Category جدید یا تغییر نوع ستون میتواند فرایند پیشبینی را مختل کند.
ذخیره مدل XGBoost
ابتدا پوشه خروجی را ایجاد میکنیم:
artifacts_dir = Path("artifacts")
artifacts_dir.mkdir(
parents=True,
exist_ok=True,
)
سپس مدل را با فرمت JSON ذخیره میکنیم:
model_path = artifacts_dir / "xgboost_classifier.json"
model.save_model(model_path)
Threshold و نام ویژگیها نیز باید همراه مدل ذخیره شوند:
metadata = {
"threshold": best_threshold,
"feature_names": feature_names,
"target_name": "target",
"best_iteration": int(model.best_iteration),
}
metadata_path = artifacts_dir / "metadata.json"
with metadata_path.open(
"w",
encoding="utf-8",
) as file:
json.dump(
metadata,
file,
ensure_ascii=False,
indent=2,
)
ذخیرهکردن صرف مدل کافی نیست. برای بازتولید درست پیشبینی باید موارد زیر نیز نگهداری شوند:
- ترتیب ویژگیها
- نوع داده ستونها
- مراحل Preprocessing
- Threshold
- نسخه کتابخانهها
- تاریخ آموزش
- شناسه دیتاست یا نسخه داده
- معیارهای ارزیابی
- تنظیمات مدل
بارگذاری مدل و انجام پیشبینی
فایل predict.py:
import json
from pathlib import Path
import pandas as pd
from xgboost import XGBClassifier
artifacts_dir = Path("artifacts")
model = XGBClassifier()
model.load_model(
artifacts_dir / "xgboost_classifier.json"
)
with (
artifacts_dir / "metadata.json"
).open("r", encoding="utf-8") as file:
metadata = json.load(file)
threshold = float(metadata["threshold"])
feature_names = metadata["feature_names"]
new_record = {
feature_name: 0.0
for feature_name in feature_names
}
input_df = pd.DataFrame([new_record])
input_df = input_df[feature_names]
probability = float(
model.predict_proba(input_df)[0, 1]
)
predicted_class = int(
probability >= threshold
)
print(
{
"probability": probability,
"threshold": threshold,
"predicted_class": predicted_class,
}
)
در پروژه واقعی باید اعتبارسنجی ورودی را قبل از اجرای مدل انجام دهید:
missing_features = set(feature_names) - set(input_df.columns)
unexpected_features = set(input_df.columns) - set(feature_names)
if missing_features:
raise ValueError(
f"Missing features: {sorted(missing_features)}"
)
if unexpected_features:
raise ValueError(
f"Unexpected features: {sorted(unexpected_features)}"
)
input_df = input_df[feature_names]
ساخت تابع قابلاستفاده در برنامه
میتوانیم پیشبینی را در یک تابع بستهبندی کنیم:
def predict_event_probability(
model: XGBClassifier,
input_data: dict,
feature_names: list[str],
threshold: float,
) -> dict:
missing_features = (
set(feature_names) - set(input_data.keys())
)
if missing_features:
raise ValueError(
f"Missing features: {sorted(missing_features)}"
)
input_df = pd.DataFrame([input_data])
input_df = input_df[feature_names]
probability = float(
model.predict_proba(input_df)[0, 1]
)
return {
"probability": round(probability, 6),
"threshold": threshold,
"predicted_class": int(
probability >= threshold
),
}
استفاده:
result = predict_event_probability(
model=model,
input_data=new_record,
feature_names=feature_names,
threshold=threshold,
)
print(result)
ترکیب XGBoost با مدلهای زبانی
XGBoost و مدلهای زبانی جایگزین مستقیم یکدیگر نیستند.
XGBoost برای تحلیل دادههای ساختاریافته مناسب است، درحالیکه مدل زبانی میتواند برای پردازش متن، استخراج اطلاعات، خلاصهسازی و تولید توضیح استفاده شود.
یک معماری ترکیبی میتواند چنین باشد:
- داده عددی و ساختاریافته وارد مدل XGBoost میشود.
- مدل احتمال یا کلاس پیشبینیشده را برمیگرداند.
- فقط اطلاعات غیرحساس و ضروری برای مدل زبانی ارسال میشود.
- مدل زبانی نتیجه را به زبان قابلفهم توضیح میدهد.
- تصمیم نهایی بر اساس منطق برنامه و بررسی انسانی انجام میشود.
مدل زبانی نباید بهصورت خودکار مقدار احتمال تولیدشده توسط XGBoost را تغییر دهد. بهتر است نقش آن به توضیح و قالببندی خروجی محدود شود.
اتصال نتیجه XGBoost به API درواره
برای استفاده از مدلهای زبانی از طریق یک API سازگار با OpenAI میتوانید از درواره استفاده کنید.
ابتدا متغیرهای محیطی را تنظیم کنید.
در Linux یا macOS:
export DARVAREH_API_KEY="YOUR_DARVAREH_API_KEY"
export DARVAREH_MODEL_ID="YOUR_MODEL_ID"
در PowerShell:
$env:DARVAREH_API_KEY="YOUR_DARVAREH_API_KEY"
$env:DARVAREH_MODEL_ID="YOUR_MODEL_ID"
سپس نتیجه مدل XGBoost را برای تولید یک توضیح کوتاه ارسال کنید:
import os
import requests
DARVAREH_API_KEY = os.environ["DARVAREH_API_KEY"]
DARVAREH_MODEL_ID = os.environ["DARVAREH_MODEL_ID"]
prediction_result = {
"probability": 0.73,
"threshold": 0.58,
"predicted_class": 1,
}
prompt = f"""
نتیجه زیر توسط یک مدل XGBoost آزمایشی تولید شده است:
{prediction_result}
در حداکثر سه جمله و به زبان فارسی توضیح بده:
1. احتمال مدل چقدر است؟
2. چرا کلاس نهایی مثبت شده است؟
3. این خروجی قطعی نیست و باید همراه با معیارهای مدل بررسی شود.
هیچ اطلاعات، علت یا ویژگی جدیدی اختراع نکن.
"""
response = requests.post(
"https://api.darvareh.ir/v1/chat/completions",
headers={
"Authorization": (
f"Bearer {DARVAREH_API_KEY}"
),
"Content-Type": "application/json",
},
json={
"model": DARVAREH_MODEL_ID,
"messages": [
{
"role": "system",
"content": (
"خروجی مدل یادگیری ماشین را "
"دقیق و بدون افزودن ادعای جدید توضیح بده."
),
},
{
"role": "user",
"content": prompt,
},
],
"temperature": 0.2,
},
timeout=60,
)
response.raise_for_status()
data = response.json()
explanation = data["choices"][0]["message"]["content"]
print(explanation)
شناسه دقیق مدل را از صفحه مدلها و قیمتهای درواره انتخاب کنید. کلید API را داخل کد، مخزن Git یا فایل قابلانتشار قرار ندهید.
در دادههای واقعی نیز بهتر است بهجای ارسال رکورد کامل کاربر، فقط خروجی مدل و اطلاعات ضروری و غیرشخصی را برای تولید توضیح ارسال کنید.
کد کامل پروژه آموزش مدل
نسخه یکپارچه فایل train.py:
from pathlib import Path
import json
import numpy as np
import pandas as pd
from sklearn.datasets import make_classification
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
from xgboost import XGBClassifier
RANDOM_STATE = 42
def build_dataset():
X_array, y_array = make_classification(
n_samples=5000,
n_features=20,
n_informative=10,
n_redundant=5,
n_repeated=0,
n_classes=2,
weights=[0.85, 0.15],
class_sep=1.2,
flip_y=0.02,
random_state=RANDOM_STATE,
)
feature_names = [
f"feature_{index:02d}"
for index in range(X_array.shape[1])
]
X = pd.DataFrame(
X_array,
columns=feature_names,
)
y = pd.Series(
y_array,
name="target",
)
return X, y, feature_names
def split_dataset(X, y):
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,
)
)
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,
)
)
return (
X_train,
X_valid,
X_test,
y_train,
y_valid,
y_test,
)
def find_best_threshold(
y_true,
probabilities,
):
thresholds = np.arange(
0.10,
0.91,
0.01,
)
scores = [
f1_score(
y_true,
(probabilities >= threshold).astype(int),
)
for threshold in thresholds
]
best_index = int(np.argmax(scores))
return (
float(thresholds[best_index]),
float(scores[best_index]),
)
def print_metrics(
title,
y_true,
probabilities,
threshold,
):
predictions = (
probabilities >= threshold
).astype(int)
print(f"\n{title}")
print(
"Accuracy:",
accuracy_score(y_true, predictions),
)
print(
"Precision:",
precision_score(y_true, predictions),
)
print(
"Recall:",
recall_score(y_true, predictions),
)
print(
"F1:",
f1_score(y_true, predictions),
)
print(
"ROC-AUC:",
roc_auc_score(y_true, probabilities),
)
print(
"Average Precision:",
average_precision_score(
y_true,
probabilities,
),
)
print(
"Confusion matrix:\n",
confusion_matrix(y_true, predictions),
)
print(
"Classification report:\n",
classification_report(
y_true,
predictions,
),
)
def main():
X, y, feature_names = build_dataset()
(
X_train,
X_valid,
X_test,
y_train,
y_valid,
y_test,
) = split_dataset(X, y)
negative_count = int(
(y_train == 0).sum()
)
positive_count = int(
(y_train == 1).sum()
)
scale_pos_weight = (
negative_count / positive_count
)
model = XGBClassifier(
objective="binary:logistic",
eval_metric="aucpr",
n_estimators=1000,
learning_rate=0.05,
max_depth=4,
min_child_weight=2,
subsample=0.80,
colsample_bytree=0.80,
reg_alpha=0.0,
reg_lambda=1.0,
scale_pos_weight=scale_pos_weight,
tree_method="hist",
early_stopping_rounds=40,
random_state=RANDOM_STATE,
n_jobs=-1,
)
model.fit(
X_train,
y_train,
eval_set=[(X_valid, y_valid)],
verbose=False,
)
valid_probabilities = (
model.predict_proba(X_valid)[:, 1]
)
best_threshold, best_f1 = (
find_best_threshold(
y_valid,
valid_probabilities,
)
)
print("Best iteration:", model.best_iteration)
print("Best validation threshold:", best_threshold)
print("Best validation F1:", best_f1)
print_metrics(
title="Validation metrics",
y_true=y_valid,
probabilities=valid_probabilities,
threshold=best_threshold,
)
test_probabilities = (
model.predict_proba(X_test)[:, 1]
)
print_metrics(
title="Test metrics",
y_true=y_test,
probabilities=test_probabilities,
threshold=best_threshold,
)
artifacts_dir = Path("artifacts")
artifacts_dir.mkdir(
parents=True,
exist_ok=True,
)
model.save_model(
artifacts_dir
/ "xgboost_classifier.json"
)
metadata = {
"threshold": best_threshold,
"feature_names": feature_names,
"target_name": "target",
"best_iteration": int(
model.best_iteration
),
}
with (
artifacts_dir / "metadata.json"
).open("w", encoding="utf-8") as file:
json.dump(
metadata,
file,
ensure_ascii=False,
indent=2,
)
print("\nArtifacts saved successfully.")
if __name__ == "__main__":
main()
اجرای پروژه:
python train.py
استفاده از XGBoost روی فایل CSV واقعی
اگر فایل شما data.csv نام دارد و ستون هدف آن target است:
import pandas as pd
data = pd.read_csv("data.csv")
X = data.drop(
columns=["target"]
)
y = data["target"]
پیش از آموزش این موارد را بررسی کنید:
print(data.head())
print(data.shape)
print(data.dtypes)
print(data.isna().sum())
print(data["target"].value_counts())
print(data["target"].value_counts(normalize=True))
همچنین باید مطمئن شوید ستونهایی که مستقیماً نتیجه آینده را آشکار میکنند داخل ویژگیها نباشند. برای مثال اگر هدف پیشبینی تکمیل یک فرایند است، ستونی که فقط پس از تکمیل همان فرایند ایجاد میشود نباید هنگام آموزش در دسترس مدل باشد. این مشکل Data Leakage نام دارد.
خطاهای رایج XGBoost
خطای No module named 'xgboost'
کتابخانه در محیط فعال نصب نشده است:
python -m pip install xgboost
برای اطمینان از یکسانبودن Python و Pip:
python -m pip show xgboost
خطای مربوط به ستونهای متنی
XGBoost نمیتواند هر نوع رشته خام را بدون مشخصشدن نوع یا Preprocessing پردازش کند.
راهحلها:
- تبدیل ستون به
categoryو فعالکردنenable_categorical - استفاده از One-hot Encoding
- استفاده از Ordinal Encoding در صورت مناسببودن
- استخراج Embedding برای متنهای طولانی
خطای ناسازگاری نام ویژگیها
مدل با یک مجموعه ستون آموزش دیده اما هنگام پیشبینی ستونهای متفاوت یا ترتیب متفاوت دریافت کرده است.
راهحل:
input_df = input_df[feature_names]
همچنین وجود و نوع تمام ستونها را پیش از پیشبینی اعتبارسنجی کنید.
آموزش بسیار کند است
راهکارهای قابلبررسی:
- استفاده از
tree_method="hist" - کاهش
n_estimators - استفاده از Early Stopping
- کاهش تعداد ویژگیهای غیرضروری
- نمونهگیری کنترلشده برای آزمایشهای اولیه
- کاهش دامنه جستوجوی پارامترها
- بررسی امکان استفاده از GPU
مدل روی Train خوب و روی Test ضعیف است
این وضعیت معمولاً نشانه Overfitting، Data Leakage یا تفاوت توزیع دادهها است.
موارد زیر را آزمایش کنید:
- کاهش
max_depth - کاهش
learning_rate - افزایش Regularization
- افزایش
min_child_weight - استفاده از
subsample - استفاده از
colsample_bytree - بررسی Leakage
- تقسیم داده بر اساس زمان، اگر داده ماهیت زمانی دارد
- بررسی تفاوت Train و Production
Accuracy بالا اما Recall پایین است
احتمالاً داده نامتوازن است یا Threshold مناسب نیست.
راهکارها:
- بررسی
scale_pos_weight - انتخاب Threshold روی Validation
- ارزیابی Precision-Recall
- استفاده از F1 یا Average Precision
- بررسی تعداد نمونههای هر کلاس
- جمعآوری داده مثبت باکیفیتتر
اشتباهات رایج در پروژههای XGBoost
استفاده از Test برای تنظیم مدل
اگر بر اساس نتیجه Test پارامترها یا Threshold را تغییر دهید، ارزیابی نهایی خوشبینانه خواهد شد.
تنظیم پارامترها قبل از ساخت Baseline
ابتدا یک Logistic Regression، Decision Tree یا Random Forest ساده بسازید. بدون Baseline مشخص نیست پیچیدگی XGBoost واقعاً چه مقدار ارزش ایجاد کرده است.
گزارشکردن فقط Accuracy
در مسئله نامتوازن، Accuracy ممکن است تصویری گمراهکننده ارائه دهد.
استفاده از Feature Importance بهعنوان علت
Feature Importance نشاندهنده نحوه استفاده مدل از ویژگیها است، نه اثبات رابطه علت و معلولی.
نادیدهگرفتن Drift
ممکن است توزیع دادههای Production با گذشت زمان تغییر کند. باید توزیع ویژگیها، نرخ کلاسها و عملکرد مدل پایش شود.
ذخیرهنکردن Preprocessing
اگر آموزش با Encoding، پاکسازی یا تبدیل ستونها انجام شده است، همان مراحل باید هنگام پیشبینی نیز دقیقاً تکرار شوند.
ارسال داده حساس به سرویسهای دیگر
برای تولید توضیح با مدل زبانی، فقط داده ضروری و غیرحساس را ارسال کنید. در بسیاری از موارد ارسال احتمال، کلاس و نام چند ویژگی عمومی کافی است.
چکلیست آمادهسازی XGBoost برای Production
پیش از استقرار مدل، موارد زیر را بررسی کنید:
- نسخه Python و کتابخانهها ثبت شده است.
- Feature Schema مشخص و نسخهبندی شده است.
- ترتیب ستونها ثابت نگه داشته میشود.
- داده ورودی اعتبارسنجی میشود.
- مقدارهای گمشده مدیریت شدهاند.
- Threshold همراه مدل ذخیره شده است.
- مدل روی Test مستقل ارزیابی شده است.
- معیارهای مناسب مسئله گزارش شدهاند.
- زمان پاسخ مدل اندازهگیری شده است.
- ورودی و خروجیها بدون ذخیره اطلاعات حساس Log میشوند.
- تغییر توزیع دادهها قابلپایش است.
- امکان بازگشت به نسخه قبلی مدل وجود دارد.
- تصمیمهای مهم فقط بر اساس یک خروجی احتمالی خودکار انجام نمیشوند.
سؤالات متداول
آیا XGBoost یک مدل هوش مصنوعی است؟
بله. XGBoost یکی از الگوریتمهای یادگیری ماشین نظارتشده است و برای طبقهبندی، رگرسیون و رتبهبندی استفاده میشود. بااینحال، یک مدل زبانی مولد مانند ChatGPT نیست.
XGBoost بهتر است یا شبکه عصبی؟
برای دادههای جدولی، XGBoost معمولاً یک گزینه پایه بسیار قدرتمند است. شبکه عصبی ممکن است روی دادههای بسیار بزرگ، چندرسانهای یا الگوهای خاص عملکرد بهتری داشته باشد. پاسخ نهایی باید با آزمایش روی دیتاست واقعی مشخص شود.
آیا XGBoost برای متن فارسی مناسب است؟
XGBoost مستقیماً متن خام را درک نمیکند. ابتدا باید متن فارسی را به ویژگیهایی مانند TF-IDF، Embedding یا خروجی یک مدل زبانی تبدیل کنید و سپس XGBoost را روی آن ویژگیها آموزش دهید.
آیا XGBoost به GPU نیاز دارد؟
خیر. بسیاری از پروژهها روی CPU اجرا میشوند. GPU میتواند برای دیتاستهای بزرگ یا جستوجوی گسترده پارامترها مفید باشد، اما پیشنیاز استفاده از XGBoost نیست.
آیا باید دادهها را نرمالسازی کنیم؟
برای مدلهای درختی XGBoost معمولاً Scaling ضروری نیست، اما پاکسازی داده، نوع درست ستونها و جلوگیری از Data Leakage همچنان ضروری است.
تفاوت predict و predict_proba چیست؟
predict کلاس نهایی را برمیگرداند. predict_proba احتمال هر کلاس را ارائه میکند و برای انتخاب Threshold، رتبهبندی و محاسبه معیارهایی مانند ROC-AUC مناسبتر است.
بهترین مقدار max_depth چیست؟
مقدار ثابتی برای همه پروژهها وجود ندارد. مقادیر ۳ تا ۸ شروع رایجی هستند، اما باید بر اساس Validation یا Cross-validation انتخاب شوند.
آیا XGBoost مقادیر گمشده را پشتیبانی میکند؟
XGBoost میتواند مقادیر گمشده را در بسیاری از سناریوها مدیریت کند، اما همچنان باید دلیل ایجاد مقدار گمشده و تفاوت آن میان Train و Production بررسی شود.
آیا میتوان مدل XGBoost را داخل API قرار داد؟
بله. میتوانید مدل ذخیرهشده را هنگام شروع برنامه بارگذاری کنید و با FastAPI، Flask یا فریمورکهای دیگر یک Endpoint برای پیشبینی بسازید.
آیا میتوان XGBoost را با API درواره ترکیب کرد؟
بله. XGBoost میتواند پیشبینی عددی یا طبقهبندی را انجام دهد و یک مدل زبانی از طریق API درواره میتواند نتیجه را خلاصه یا به زبان طبیعی توضیح دهد. بهتر است محاسبه اصلی و منطق تصمیمگیری همچنان در کد برنامه باقی بماند.
جمعبندی
XGBoost یکی از مهمترین ابزارهای یادگیری ماشین برای دادههای جدولی است. این کتابخانه با ترکیب چندین درخت تصمیم، اصلاح تدریجی خطاها و استفاده از Regularization میتواند مدلهایی دقیق و قابلاستفاده برای طبقهبندی، رگرسیون و رتبهبندی ایجاد کند.
برای ساخت یک پروژه قابلاعتماد نباید فقط روی انتخاب الگوریتم تمرکز کرد. تقسیم صحیح Train، Validation و Test، جلوگیری از Data Leakage، انتخاب معیار مناسب، تنظیم Threshold، ثبت Feature Schema و پایش دادههای Production بهاندازه خود مدل اهمیت دارند.
بهترین مسیر عملی این است که ابتدا یک Baseline ساده بسازید، سپس XGBoost را با تنظیمات محدود آزمایش کنید، از Early Stopping بهره ببرید و تنها در صورت وجود بهبود واقعی، مدل پیچیدهتر را وارد Production کنید.
اگر میخواهید قابلیتهای مدلهای زبانی را در کنار مدلهای یادگیری ماشین به نرمافزار خود اضافه کنید، در درواره میتوانید به API مدلهای مختلف دسترسی داشته باشید. برای انتخاب مدل و مشاهده هزینه بهروز، صفحه مدلها و قیمتهای درواره را ببینید.
مقالات مرتبط
- آموزش هوش مصنوعی با پایتون و API درواره
- تحلیل فایل CSV با هوش مصنوعی
- راهنمای ارزیابی مدلهای هوش مصنوعی و Evals
- آموزش Inference در هوش مصنوعی
- راهنمای مدلهای هوش مصنوعی
- آموزش دریافت API Key هوش مصنوعی از درواره
برای مطالعه شرایط استفاده و محدودیتهای مسئولیت، صفحه «سلب مسئولیت» را مشاهده کنید.