HLTV kill-count prediction (pairwise: which player gets more kills)
Models from the report REPORT_P4_kills.pdf: given a CS2 map, predict for every pair of the ten players
who will finish with more kills. Two regimes:
| regime | model | pairwise accuracy |
|---|---|---|
| pre-match (before a single round) | XGBoost (3 seeds) + logistic blend, 88 features | 61.1 % (n=107,300 pairs, 10 expanding-origin quarters) |
| in-play, first k rounds known | token transformer over per-round per-player features | k=3 68.6 · k=5 72.1 · k=8 76.1 · k=12 81.6 · k=15 86.1 · k=18 90.7 |
Baselines: naive career kill-rate 58.0 %, market/rating 59.4 %. Pre-match full-coverage accuracy is capped near 60 % by the between-player variance (ICC = 0.045; a Gamma-Poisson player model tops out at 60.4 %), so the pre-match model is essentially at the information ceiling; 80 % pre-match is impossible and the achievable route is a selective one (90 % accuracy on the top 1 % most confident pairs, 80 % on top 8 %).
Files
prematch_features.parquet 154,550 labelled player pairs x 88 features (+ ids and the label y)
artifacts/prematch_xgb_s{0,1,2}.json xgboost boosters (88 features, 700 rounds)
artifacts/prematch_lr.joblib StandardScaler + LogisticRegression(C=.3)
artifacts/prematch_meta.joblib feature order, NaN-imputation medians, confidence tiers
score = 0.5*mean(xgb seeds) + 0.5*logistic
round_tokens.npz input tensor for the in-play model
artifacts/token_ck{K}/qALL_s{0..3}.pt in-play transformer, 4 seeds, d=96, mask cut after round K
tokS_ck{K}.npz the cross-validated predictions behind every published number
set_data.npz, artifacts/set/qALL_s{0..3}.pt alternative 10-player set transformer (weaker, r=0.62)
results/*.json every number in the report, machine-readable
REPORT_P4_kills.pdf the full write-up
tools/prematch_predict.py score the saved pre-match model
tools/inplay_predict.py score the saved in-play transformer at checkpoint k (map-ix / match / all)
tools/set_predict.py score the saved set transformer
tools/kp_paths.py repo layout resolution (no database, no refit needed anywhere)
Usage
pip install torch xgboost scikit-learn joblib numpy pandas pyarrow
python tools/prematch_predict.py # 154,550 pairs, prints accuracy / AUC of the shipped model
python tools/prematch_predict.py --match 2400011
python tools/inplay_predict.py --ck 12 --map-ix 0 # predicted kills + pairwise ordering for one map
python tools/inplay_predict.py --ck 12 --all --out pred_ck12.csv
python tools/set_predict.py --map-ix 0
round_tokens.npz holds, per player per round, 23 features
(k d dmg hits fl_enemy gr_n sp_n won is_t1 sd ck cd cdmg ri f20_kp24 f5_kp24 f20_share f20_awp_sh f20_opener f20_surv pmap_share r_shrunk gshare — round kills/deaths/damage/hits, flashes and grenades, round result and
side, cumulative kills/deaths, round index, plus static pre-match per-player profiles and shared context), together
with the round validity mask M, the final kill count Y, the quarter Q used for the expanding-origin folds,
and mid / map_id / slot / player ids. Feature order is also stored in each .pt payload (nf, norm_mu,
norm_sd).
Caveats
- The
artifacts/weights are all-data retrains for production scoring. Every accuracy figure above comes from expanding-origin cross-validation by quarter (10 test quarters, latest matches from 2026); scoring a match that is inside the training window with these weights is in-sample and will look far better than it is. - Weight files ship no leakage of the label: the round mask is applied before the features of later rounds are visible, and the checkpoint-specific weights are the ones trained with that mask (a mask mismatch is the bug that produced a fake 98 % in an early version of this work).
- Kill counts tie 5.7 % of the time; ties are scored as half-correct in the accuracy figures.
- Data: HLTV match pages, 8,235 maps, 1,185,199 labelled kills, 99.0 % linked to a player_id.