193 lines
5.4 KiB
Python
Executable File
193 lines
5.4 KiB
Python
Executable File
"""
|
|
Card Market XGBoost Model Trainer
|
|
==================================
|
|
Kart (4.5 Alt/Üst, 5.5 Alt/Üst) için XGBoost modeli eğitir.
|
|
|
|
Usage:
|
|
python3 scripts/train_cards_model.py
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
import pickle
|
|
import numpy as np
|
|
import pandas as pd
|
|
import xgboost as xgb
|
|
from sklearn.model_selection import train_test_split, StratifiedKFold
|
|
from sklearn.metrics import accuracy_score, log_loss, roc_auc_score, classification_report
|
|
|
|
# Config
|
|
AI_ENGINE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
DATA_PATH = os.path.join(AI_ENGINE_DIR, "data", "training_data_cards.csv")
|
|
MODELS_DIR = os.path.join(AI_ENGINE_DIR, "models", "xgboost")
|
|
|
|
os.makedirs(MODELS_DIR, exist_ok=True)
|
|
|
|
# Feature columns
|
|
FEATURES = [
|
|
# Referee features
|
|
"ref_matches",
|
|
"ref_avg_yellow",
|
|
"ref_avg_red",
|
|
"ref_avg_total",
|
|
|
|
# Team features
|
|
"home_team_matches",
|
|
"home_team_avg_cards",
|
|
"away_team_matches",
|
|
"away_team_avg_cards",
|
|
|
|
# League features
|
|
"league_avg_cards",
|
|
"league_match_count",
|
|
|
|
# Derived
|
|
"combined_team_avg",
|
|
"ref_team_combined",
|
|
]
|
|
|
|
|
|
def load_data():
|
|
if not os.path.exists(DATA_PATH):
|
|
print(f"❌ Data file not found: {DATA_PATH}")
|
|
print(" Run extract_card_training_data.py first!")
|
|
sys.exit(1)
|
|
|
|
print(f"📦 Loading data from {DATA_PATH}...")
|
|
df = pd.read_csv(DATA_PATH)
|
|
df.fillna(0, inplace=True)
|
|
print(f" Shape: {df.shape}")
|
|
return df
|
|
|
|
|
|
def train_card_model(df, target_col, model_name):
|
|
"""Kart modeli eğit"""
|
|
|
|
print(f"\n🚀 Training {model_name} (Target: {target_col})...")
|
|
|
|
# Filter valid rows
|
|
valid_df = df[df[target_col].notna()].copy()
|
|
if valid_df.empty:
|
|
print(f" ⚠️ No valid data for {target_col}, skipping.")
|
|
return None
|
|
|
|
X = valid_df[FEATURES]
|
|
y = valid_df[target_col].astype(int)
|
|
|
|
print(f" Target distribution: {dict(y.value_counts())}")
|
|
|
|
# Split
|
|
X_train, X_test, y_train, y_test = train_test_split(
|
|
X, y, test_size=0.2, random_state=42, stratify=y
|
|
)
|
|
|
|
# Model params
|
|
params = {
|
|
'objective': 'binary:logistic',
|
|
'eval_metric': 'logloss',
|
|
'eta': 0.05,
|
|
'max_depth': 5,
|
|
'subsample': 0.8,
|
|
'colsample_bytree': 0.8,
|
|
'min_child_weight': 3,
|
|
'nthread': 4,
|
|
'seed': 42
|
|
}
|
|
|
|
# Train with cross-validation
|
|
skf = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
|
|
cv_scores = []
|
|
|
|
for fold, (train_idx, val_idx) in enumerate(skf.split(X_train, y_train)):
|
|
X_t, X_v = X_train.iloc[train_idx], X_train.iloc[val_idx]
|
|
y_t, y_v = y_train.iloc[train_idx], y_train.iloc[val_idx]
|
|
|
|
dtrain = xgb.DMatrix(X_t, label=y_t, feature_names=FEATURES)
|
|
dval = xgb.DMatrix(X_v, label=y_v, feature_names=FEATURES)
|
|
|
|
model = xgb.train(
|
|
params,
|
|
dtrain,
|
|
num_boost_round=500,
|
|
evals=[(dval, 'eval')],
|
|
early_stopping_rounds=30,
|
|
verbose_eval=False
|
|
)
|
|
|
|
preds = model.predict(dval)
|
|
auc = roc_auc_score(y_v, preds)
|
|
cv_scores.append(auc)
|
|
print(f" Fold {fold+1} AUC: {auc:.4f}")
|
|
|
|
print(f" Mean CV AUC: {np.mean(cv_scores):.4f} (+/- {np.std(cv_scores):.4f})")
|
|
|
|
# Train final model on all training data
|
|
dtrain_full = xgb.DMatrix(X_train, label=y_train, feature_names=FEATURES)
|
|
dtest = xgb.DMatrix(X_test, label=y_test, feature_names=FEATURES)
|
|
|
|
final_model = xgb.train(
|
|
params,
|
|
dtrain_full,
|
|
num_boost_round=300,
|
|
verbose_eval=False
|
|
)
|
|
|
|
# Evaluate
|
|
test_preds = final_model.predict(dtest)
|
|
test_pred_class = (test_preds > 0.5).astype(int)
|
|
|
|
acc = accuracy_score(y_test, test_pred_class)
|
|
auc = roc_auc_score(y_test, test_preds)
|
|
|
|
print(f"\n📊 Test Results:")
|
|
print(f" Accuracy: {acc:.4f}")
|
|
print(f" AUC: {auc:.4f}")
|
|
print(classification_report(y_test, test_pred_class))
|
|
|
|
# Feature importance
|
|
importance = final_model.get_score(importance_type='gain')
|
|
print(f"\n🔍 Top Features:")
|
|
sorted_importance = sorted(importance.items(), key=lambda x: x[1], reverse=True)[:5]
|
|
for feat, score in sorted_importance:
|
|
print(f" {feat}: {score:.2f}")
|
|
|
|
# Save model
|
|
model_path = os.path.join(MODELS_DIR, f"xgb_{model_name.lower()}.json")
|
|
final_model.save_model(model_path)
|
|
print(f"\n💾 Model saved to: {model_path}")
|
|
|
|
return final_model
|
|
|
|
|
|
def main():
|
|
df = load_data()
|
|
|
|
# Train multiple card models
|
|
models = []
|
|
|
|
# 1. Cards Over 4.5
|
|
model_45 = train_card_model(df, "label_cards_over45", "cards45")
|
|
models.append(("cards_over_45", model_45))
|
|
|
|
# 2. Cards Over 3.5
|
|
model_35 = train_card_model(df, "label_cards_over35", "cards35")
|
|
models.append(("cards_over_35", model_35))
|
|
|
|
# 3. Cards Over 5.5
|
|
model_55 = train_card_model(df, "label_cards_over55", "cards55")
|
|
models.append(("cards_over_55", model_55))
|
|
|
|
print("\n" + "="*60)
|
|
print("✅ All card models trained successfully!")
|
|
print(f"📁 Models saved to: {MODELS_DIR}")
|
|
|
|
# List saved files
|
|
import glob
|
|
card_files = glob.glob(os.path.join(MODELS_DIR, "xgb_cards*.json"))
|
|
for f in card_files:
|
|
print(f" - {os.path.basename(f)}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|