Game State Features#

Navigation: ← Previous: Introduction | Next: DLS & Resource Methods →

We encode each ball in the chase as a feature vector for modelling.

import sys
from pathlib import Path
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import warnings
warnings.filterwarnings('ignore')
plt.style.use('seaborn-v0_8-whitegrid')

PROJ_DIR = Path('.').resolve()
if not (PROJ_DIR / 'cricsheet_utils.py').exists():
    PROJ_DIR = Path('projects/cricket-win-probability').resolve()
if str(PROJ_DIR) not in sys.path:
    sys.path.insert(0, str(PROJ_DIR))

from cricsheet_utils import (
    project_data_dir, load_cricsheet_json, match_metadata, balls_to_dataframe,
    build_game_states, cumulative_runs_by_innings, resource_remaining,
    dls_win_probability,
)
DATA_DIR = project_data_dir()
SAMPLE_DIR = DATA_DIR / 'sample_matches'
training = pd.read_csv(DATA_DIR / 'odi_training_sample.csv')
feature_cols = [
    'runs_scored', 'wickets_lost', 'balls_bowled', 'balls_remaining',
    'wickets_remaining', 'runs_required', 'runs_required_per_ball',
    'current_run_rate', 'target', 'overs_completed',
    'phase_powerplay', 'phase_middle', 'phase_death',
]
training[feature_cols].describe().T
count mean std min 25% 50% 75% max
runs_scored 120000.0 132.790708 77.812029 0.000000 66.000000 132.000000 198.000000 322.0
wickets_lost 120000.0 3.146100 2.187440 0.000000 1.000000 3.000000 5.000000 8.0
balls_bowled 120000.0 150.500000 86.602420 1.000000 75.750000 150.500000 225.250000 300.0
balls_remaining 120000.0 149.500000 86.602420 0.000000 74.750000 149.500000 224.250000 299.0
wickets_remaining 120000.0 6.853900 2.187440 2.000000 5.000000 7.000000 9.000000 10.0
runs_required 120000.0 142.649092 78.515024 0.000000 76.000000 142.000000 208.000000 341.0
runs_required_per_ball 120000.0 1.374173 5.067772 0.000000 0.862903 0.954887 1.072917 99.0
current_run_rate 120000.0 5.286491 1.054857 0.000000 4.813187 5.288136 5.740385 30.0
target 120000.0 275.375000 22.463161 220.000000 260.000000 276.000000 290.250000 341.0
overs_completed 120000.0 25.083333 14.433737 0.166667 12.625000 25.083333 37.541667 50.0
phase_powerplay 120000.0 0.200000 0.400002 0.000000 0.000000 0.000000 0.000000 1.0
phase_middle 120000.0 0.580000 0.493561 0.000000 0.000000 1.000000 1.000000 1.0
phase_death 120000.0 0.220000 0.414248 0.000000 0.000000 0.000000 0.000000 1.0

Correlation structure#

corr = training[feature_cols + ['batting_team_won']].corr()
fig, ax = plt.subplots(figsize=(9, 7))
im = ax.imshow(corr, cmap='RdBu_r', vmin=-1, vmax=1)
ax.set_xticks(range(len(corr)))
ax.set_yticks(range(len(corr)))
ax.set_xticklabels(corr.columns, rotation=90, fontsize=8)
ax.set_yticklabels(corr.columns, fontsize=8)
plt.colorbar(im, ax=ax)
ax.set_title('Feature correlation matrix')
plt.tight_layout()
plt.show()
../../_images/e5ea0bbb27eda80364b2354e5436f1089836844a0848378ecf248d013a81b0f3.png

RRR vs outcome at the final ball#

finals = training.groupby('match_idx').tail(1)
fig, ax = plt.subplots(figsize=(8, 4))
for won, grp in finals.groupby('batting_team_won'):
    label = 'Chase won' if won else 'Chase lost'
    ax.hist(grp['runs_required_per_ball'].dropna(), bins=30, alpha=0.6, label=label)
ax.set_xlabel('RRR at last ball')
ax.set_ylabel('Matches')
ax.legend()
ax.set_title('Final-ball required rate by outcome')
plt.tight_layout()
plt.show()
../../_images/417f0c8e6f703f1dc49f71321d1339ca41d2e93066a0ea6583ad644a3777fdc3.png

Example: high-pressure state#

pressure = training[(training['over'] >= 43) & (training['wickets_lost'] >= 5)]
pressure.nlargest(1, 'runs_required_per_ball')[feature_cols + ['batting_team_won']]
runs_scored wickets_lost balls_bowled balls_remaining wickets_remaining runs_required runs_required_per_ball current_run_rate target overs_completed phase_powerplay phase_middle phase_death batting_team_won
299 228 6 300 0 4 6 99.0 4.56 234 50.0 0 0 1 1

Navigation: ← Previous: Introduction | Next: DLS & Resource Methods →