Predict a chess player's Elo rating from a single PGN. Engine-derived move-quality and time-usage features feed gradient-boosted tree regressors and benchmarked against a linear baseline.
- Extract - stream-sample the Lichess Jan 2026 database (
src/extract_games.py) → 140k games. - Evaluate - fill missing positions with Stockfish 17 via Node (
app/scripts/evaluate-games.mjs). - Features - 27 predictors per player-game (
src/create_features.py). - Train + evaluate -
src/train_model.py,src/evaluate_model.py.
pip install -r requirements.txt # needs catboost, xgboost, lightgbm, scikit-learn
cd app && npm install # for Stockfish evaluation steppython3 run.py --model xgboost # one model
python3 run.py --all # all four
python3 run.py --all --tune # with Optuna tuningPlots are written to figures/, trained models to models/.
Held-out test set (28k player-games). MAE/RMSE in Elo points.
| Model | MAE | RMSE | R² |
|---|---|---|---|
| XGBoost | 223.96 | 279.68 | 0.4525 |
| CatBoost | 224.08 | 279.57 | 0.4529 |
| LightGBM | 224.66 | 280.79 | 0.4481 |
| Linear | 241.38 | 299.79 | 0.3709 |
The GBDTs beat the linear baseline by ~17 MAE. Error is lowest mid-distribution (1200–1800) and grows at the tails (2400+ MAE ≈ 550), consistent with engine-feature saturation at high Elo.