پیشرفتهml

Random Forest و XGBoost

15 دقیقه
Random Forest و XGBoost

مدل‌های ensemble برای پیش‌بینی.

Random Forest و XGBoost: مدل‌های Ensemble برای پیش‌بینی بازارهای مالی

هدف یادگیری

پس از مطالعه این درس، قادر خواهید بود:
- معماری ریاضی Random Forest و XGBoost را درک کرده و تفاوت‌های بنیادین آن‌ها را توضیح دهید.
- توابع loss و مکانیزم gradient boosting را برای داده‌های سری زمانی مالی فرموله کنید.
- هایپرپارامترهای کلیدی هر دو مدل را برای داده‌های OHLCV بهینه‌سازی کنید.
- Feature importance را تفسیر کرده و از آن برای ساخت سیگنال تریدینگ استفاده کنید.

---

۱. پایه‌های Ensemble Learning: چرا یک مدل کافی نیست؟

در بازارهای مالی، هیچ مدل تکی نمی‌تواند تمام الگوهای پنهان در داده را کشف کند. این مشکل را با مفهوم bias-variance tradeoff می‌شناسیم:

$$\text{MSE}(\hat{f}) = \text{Bias}^2(\hat{f}) + \text{Var}(\hat{f}) + \sigma^2_\epsilon$$

یک مدل ساده (مثل درخت تصمیم کم‌عمق) بایاس بالا دارد و الگوهای پیچیده بازار را از دست می‌دهد. یک مدل عمیق واریانس بالا دارد و به نوید داده‌های آموزشی overfit می‌شود.

روش‌های Ensemble این معضل را با ترکیب چندین مدل ضعیف حل می‌کنند. دو رویکرد اصلی وجود دارد:

- Bagging (Bootstrap Aggregating): مدل‌ها موازی آموزش می‌بینند و نتایجشان میانگین‌گیری می‌شود → Random Forest
- Boosting: مدل‌ها سری آموزش می‌بینند و هر مدل اشتباهات مدل قبلی را اصلاح می‌کند → XGBoost

در بازار کریپتو که نوسان ذاتی و رژیم‌های مختلف (trending, ranging, volatile) وجود دارد، این تمایز اهمیت بسیار زیادی پیدا می‌کند.

---

۲. Random Forest: ریاضیات Bagging و Decorrelation

ساختار معماری

Random Forest مجموعه‌ای از $B$ درخت تصمیم است که هر کدام روی یک bootstrap sample آموزش دیده‌اند. پیش‌بینی نهایی برای رگرسیون:

$$\hat{f}_{RF}(x) = \frac{1}{B} \sum_{b=1}^{B} T_b(x)$$

واریانس این estimator:

$$\text{Var}\left(\frac{1}{B}\sum_{b=1}^{B} T_b\right) = \frac{\rho \sigma^2 (B-1) + \sigma^2}{B} = \sigma^2\left(\rho + \frac{1-\rho}{B}\right)$$

که $\rho$ همبستگی بین درختان و $\sigma^2$ واریانس هر درخت است. با $B \to \infty$، واریانس به $\rho\sigma^2$ میل می‌کند. بنابراین کاهش همبستگی بین درختان (decorrelation) کلید اصلی موفقیت است.

Random Forest این کار را با random feature selection انجام می‌دهد: در هر split، فقط $m = \sqrt{p}$ ویژگی از $p$ ویژگی کل بررسی می‌شود.

Out-of-Bag Error و اهمیت آن در مالی

هر درخت روی ~63% داده‌ها (bootstrap) آموزش می‌بیند. داده‌های باقیمانده (OOB) یک ارزیابی unbiased بدون نیاز به validation set جداگانه می‌دهند:

$$\text{OOB Error} = \frac{1}{N}\sum_{i=1}^{N}\left(y_i - \hat{f}^{(-i)}(x_i)\right)^2$$

در داده‌های سری زمانی مالی، این ویژگی مهم است چون نمی‌توان به سادگی داده را به train/test تقسیم کرد بدون اینکه temporal leakage ایجاد شود.

Feature Importance در Random Forest

دو روش اصلی وجود دارد:

۱. MDI (Mean Decrease in Impurity):
$$\text{Imp}(X_j) = \frac{1}{B}\sum_{b=1}^{B}\sum_{t \in T_b : v(t)=j} p(t) \cdot \Delta I(t)$$

که $p(t)$ نسبت نمونه‌های رسیده به گره $t$ و $\Delta I(t)$ کاهش ناخالصی است.

۲. MDA (Mean Decrease in Accuracy / Permutation Importance): ویژگی $j$ را permute کرده و کاهش دقت را اندازه می‌گیریم. این روش bias کمتری دارد و برای ویژگی‌های با cardinality بالا (مثل volume در کریپتو) قابل اعتمادتر است.

---

۳. XGBoost: Gradient Boosting با بهینه‌سازی دقیق

فرمول‌بندی کلی Boosting

در Gradient Boosting، مدل به صورت additive ساخته می‌شود:

$$\hat{y}_i^{(t)} = \hat{y}_i^{(t-1)} + \eta \cdot h_t(x_i)$$

که $h_t$ درخت جدید و $\eta$ learning rate است. هر درخت جدید برای minimize کردن loss روی residuals آموزش می‌بیند:

$$L^{(t)} = \sum_{i=1}^{N} l\left(y_i, \hat{y}_i^{(t-1)} + h_t(x_i)\right) + \Omega(h_t)$$

بسط Taylor و نوآوری XGBoost

XGBoost با بسط Taylor مرتبه دوم، تابع هدف را تقریب می‌زند:

$$L^{(t)} \approx \sum_{i=1}^{N}\left[l(y_i, \hat{y}^{(t-1)}) + g_i h_t(x_i) + \frac{1}{2}h_i h_t^2(x_i)\right] + \Omega(h_t)$$

که:
- $g_i = \partial_{\hat{y}^{(t-1)}} l(y_i, \hat{y}^{(t-1)})$ — gradient (شبیه residual اما کلی‌تر)
- $h_i = \partial^2_{\hat{y}^{(t-1)}} l(y_i, \hat{y}^{(t-1)})$ — hessian (اطلاعات curvature)

ترم regularization:
$$\Omega(h) = \gamma T + \frac{1}{2}\lambda\sum_{j=1}^{T}w_j^2$$

که $T$ تعداد برگ‌ها و $w_j$ وزن هر برگ است.

مقدار بهینه برگ‌ها

پس از ساده‌سازی، وزن بهینه برگ $j$:

$$w_j^* = -\frac{G_j}{H_j + \lambda}$$

و gain بهینه برای هر split:

$$\text{Gain} = \frac{1}{2}\left[\frac{G_L^2}{H_L+\lambda} + \frac{G_R^2}{H_R+\lambda} - \frac{(G_L+G_R)^2}{H_L+H_R+\lambda}\right] - \gamma$$

این معادله دقیقاً می‌گوید XGBoost چه زمانی یک split انجام می‌دهد: وقتی gain بزرگتر از $\gamma$ باشد. این پارامتر $\gamma$ مستقیماً عمق درخت و پیچیدگی مدل را کنترل می‌کند.

---

۴. کاربرد در بازار کریپتو: Feature Engineering و Target Definition

تعریف Target متناسب با بازار

انتخاب target در مالی از ساختار مدل مهم‌تر است. چند رویکرد:

بازده لگاریتمی:
$$r_t = \ln\left(\frac{P_{t+h}}{P_t}\right)$$

Triple-Barrier Method (پیشنهاد لوپز د پرادو):
به جای پیش‌بینی بازده خام، label به سه دسته تقسیم می‌شود:
- +1: قیمت به take-profit برسد قبل از stop-loss
- -1: قیمت به stop-loss برسد قبل از take-profit
- 0: در بازه زمانی مشخص هیچکدام لمس نشود

این روش برای کریپتو که نوسان شدید دارد بسیار مناسب‌تر از regression خام است.

Feature Engineering برای OHLCV

ویژگی‌های استاندارد برای مدل‌های ensemble:

python

Technical Features


features = [
'rsi_14', 'rsi_7',
'macd_signal', 'macd_hist',
'bb_width', # Bollinger Band width
'atr_14', # Average True Range
'volume_ratio', # volume / rolling_mean(volume, 20)
'obv_slope', # On-Balance Volume slope
# Microstructure
'spread_pct', # (high - low) / close
'close_location', # (close - low) / (high - low)
# Regime Features
'realized_vol_20',
'vol_of_vol', # std(realized_vol)
'trend_strength', # ADX
]

نکته مهم برای سری زمانی: همه features باید از lag استفاده کنند تا از look-ahead bias جلوگیری شود:

python
df['rsi_14'] = df['rsi_14'].shift(1) # از کندل قبل استفاده کن

---

۵. پیاده‌سازی و بهینه‌سازی هایپرپارامترها

Purged Cross-Validation برای داده‌های مالی

استفاده از k-fold standard در سری زمانی منجر به information leakage می‌شود. باید از Purged Walk-Forward CV استفاده کرد:

python
from sklearn.model_selection import TimeSeriesSplit

tscv = TimeSeriesSplit(
n_splits=5,
gap=24 # 24 ساعت فاصله بین train و test
)

هایپرپارامترهای کلیدی Random Forest

| پارامتر | محدوده توصیه‌شده | تأثیر |
|---------|-----------------|-------|
| n_estimators | 200–1000 | واریانس را کاهش می‌دهد |
| max_features | sqrt(p) تا log2(p) | decorrelation درختان |
| max_depth | 5–15 | overfitting |
| min_samples_leaf | 5–50 | regularization |

هایپرپارامترهای کلیدی XGBoost

| پارامتر | محدوده توصیه‌شده | تأثیر |
|---------|-----------------|-------|
| learning_rate | 0.01–0.1 | speed vs. quality |
| n_estimators | 500–2000 | با early stopping |
| max_depth | 3–7 | complexity |
| subsample | 0.6–0.9 | مانع overfitting |
| colsample_bytree | 0.5–0.8 | feature randomization |
| gamma | 0–5 | minimum split gain |
| lambda | 1–10 | L2 regularization |

python
xgb_params = {
'objective': 'binary:logistic', # برای classification
'eval_metric': 'logloss',
'learning_rate': 0.05,
'n_estimators': 1000,
'max_depth': 5,
'subsample': 0.8,
'colsample_bytree': 0.7,
'gamma': 1.0,
'lambda': 2.0,
'early_stopping_rounds': 50
}

SHAP Values برای تفسیر مدل

برای درک اینکه چرا مدل یک پیش‌بینی خاص داده، از SHAP (SHapley Additive exPlanations) استفاده می‌کنیم:

$$\phi_i(f) = \sum_{S\subseteq F\setminus\{i\}} \frac{|S|!(|F|-|S|-1)!}{|F|!}\left[f(S\cup\{i\}) - f(S)\right]$$

SHAP مقدار کمک واقعی هر feature به پیش‌بینی را محاسبه می‌کند. برای تریدینگ این به معنی فهمیدن است که آیا RSI، volume، یا volatility در یک لحظه خاص بیشترین تأثیر را داشته‌اند.

---

۶. مقایسه عملی و انتخاب مدل مناسب

Random Forest بهتر است وقتی:

- داده‌های کم داریم (overfitting کمتر) - سرعت inference مهم است (parallelizable) - features دارای nonlinear interactions هستند - رژیم‌های بازار ناپایدار و شدید هستند (robustness)

XGBoost بهتر است وقتی:

- داده‌های زیاد با noise کم داریم - دقت بالا اولویت است - می‌خواهیم روابط ضعیف‌تر بین features کشف شوند - custom loss function داریم (مثل Sharpe-based loss)

Custom Loss برای مالی

یکی از مزایای XGBoost امکان تعریف custom objective است. برای maximize کردن Sharpe ratio به جای minimize کردن MSE:

python
def sharpe_objective(y_pred, dtrain):
y_true = dtrain.get_label()
returns = y_true * np.sign(y_pred)
sharpe = returns.mean() / (returns.std() + 1e-8)

# Gradient
grad = -y_true / (returns.std() + 1e-8)
# Hessian (تقریب)
hess = np.ones_like(grad) * 0.01
return grad, hess

این رویکرد مدل را مستقیماً برای هدف مالی (نه statistical accuracy) بهینه می‌کند.

---

نتیجه‌گیری

Random Forest و XGBoost دو ابزار قدرتمند ensemble هستند که هر کدام معماری متفاوتی برای مقابله با bias-variance tradeoff دارند. Random Forest با parallelism و robustness، و XGBoost با دقت بالا و انعطاف در تعریف objective، هر دو در arsenal یک quant trader جایگاه دارند.

تفاوت اصلی در تولید پول‌ساز نهایی نیست — بلکه در feature engineering و target definition است. مدل‌های ensemble نیرومند هستند اما بدون triple-barrier labeling، purged cross-validation، و SHAP analysis، به سادگی overfit می‌شوند و در live trading عملکرد ضعیف دارند.

---

خلاصه نقطه‌ای

- Bagging (RF) vs. Boosting (XGBoost): موازی با decorrelation در برابر سری با error correction
- فرمول کلیدی RF: واریانس نهایی به $\rho\sigma^2$ میل می‌کند — کاهش $\rho$ با random feature selection
- فرمول کلیدی XGBoost: وزن بهینه برگ $w^* = -G_j/(H_j+\lambda)$ و gain هر split با hessian تنظیم می‌شود
- Target: Triple-barrier method برای کریپتو بهتر از regression خام است
- Validation: Purged Walk-Forward CV اجباری است — k-fold standard منجر به data leakage می‌شود
- Interpretability: SHAP values سهم واقعی هر feature را با مبنای تئوری بازی محاسبه می‌کند
- Custom Loss: XGBoost اجازه می‌دهد مستقیماً برای Sharpe یا سایر متریک‌های مالی بهینه‌سازی کنیم
- انتخاب مدل: RF برای robustness و کم‌داده، XGBoost برای دقت و داده‌های فراوان

Random Forest و XGBoost | آکادمی تریدیار | تریدیار