Skip to content
sv6095Public

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

43 Commits

Folders and files

Repository files navigation

AuctionIQ — IPL Player Valuation & Franchise Spend Efficiency

A data-driven valuation engine that prices IPL players on performance fundamentals, flags auction over/underpayment, and quantifies spend efficiency across franchises — built end-to-end using SQL, Python, Excel, and Power BI.


Project Overview

Every IPL auction, franchises collectively spend Rs. 500+ crore on players in a matter of days, often driven by bidding-war psychology rather than fundamentals. This project answers one core business question:

What should a player actually be worth based on performance — and which franchises are systematically over- or under-paying?

This is framed as a valuation and capital allocation problem, not a machine learning demo. The same underlying logic applies to pricing a private asset, negotiating a signing bonus, or setting a product price point.


Table of Contents


Data Sources

Dataset Provider Coverage Records
IPL Auction Data (2013-2026) sunnyyadav754 / Kaggle 14 seasons, one CSV per year 1,380 sold players
Ball-by-Ball Performance jamiewelsh2 / Cricsheet IPL 2008-2023 239,693 delivery rows

No data synthesis. Every player name, price, and performance number is sourced directly from the above datasets. All auction prices are in Indian Rupees (Lakh). The 2013 dataset originally uses USD and is converted at a fixed Rs. 55/USD rate to match later seasons.


Project Structure

ipl/
|
+-- data/
|   +-- seed_data.py                    # Master ingestion script - run this first
|   +-- ipl_valuation.db                # SQLite star schema (output)
|   +-- raw/
|   |   +-- auction_sunny/              # Kaggle auction CSVs (2013-2026)
|   |   +-- ball_by_ball_ipl.csv        # Cricsheet ball-by-ball data
|   +-- processed/
|       +-- auction_features.csv        # 1,380 x 37 anti-leakage feature matrix
|       +-- player_season_stats.csv     # Per-player, per-season aggregates
|       +-- model_features.csv          # Model-ready features (scaled)
|       +-- model_output.csv            # Walk-forward predictions + residuals
|       +-- feature_importances.csv     # XGBoost feature importance scores
|       +-- franchise_efficiency.csv    # Per-franchise overpayment summary
|
+-- sql/
|   +-- schema.sql                      # Star schema DDL
|   +-- pre_auction_stats.sql           # Anti-leakage performance aggregates
|   +-- franchise_spend_summary.sql     # Franchise efficiency queries
|
+-- notebooks/
|   +-- 01_data_merge.ipynb             # Load from SQLite, validate joins
|   +-- 02_feature_engineering.ipynb    # Role-aware imputation, interactions
|   +-- 03_valuation_model.ipynb        # XGBoost + walk-forward CV
|   +-- 04_insight_generation.ipynb     # Franchise efficiency, hypothesis tests
|
+-- dashboard/
|   +-- generate_dashboard.py           # Plotly HTML dashboard generator
|   +-- generate_powerbi.py             # Power BI .pbit template generator
|   +-- ipl_dashboard.html              # PRIMARY DELIVERABLE - open in browser
|   +-- ipl_dashboard.pbit             # Power BI Desktop template
|
+-- excel/
|   +-- generate_excel.py               # Excel workbook generator
|   +-- valuation_sanity_check.xlsx     # Analyst sanity-check workbook
|
+-- deliverable/
|   +-- generate_pptx.py                # PPTX recommendation generator
|   +-- ipl_recommendation.pptx         # 1-page business recommendation
|   +-- charts/                         # Static PNGs exported from notebooks
|       +-- 01_price_distribution.png
|       +-- 02_correlation_heatmap.png
|       +-- 02_log_transform.png
|       +-- 03_feature_importance.png
|       +-- 03_model_performance.png
|       +-- 04_franchise_efficiency.png
|       +-- 04_market_efficiency_trend.png
|       +-- 04_overpaid_underpaid_xi.png
|
+-- requirements.txt

Architecture

Database — SQLite Star Schema

                  +-----------------+
                  |   dim_player    |
                  |  player_id (PK) |
                  |  player_name    |
                  |  nationality    |
                  |  role           |
                  +--------+--------+
                           |
+---------------+   +------+----------+   +----------------+
|  dim_season   |   |  fact_auction   |   |   dim_team     |
|  season (PK)  +---|  player_id (FK) +---|  team_id (PK)  |
|  year         |   |  season (FK)    |   |  team_name     |
|  auction_type |   |  team_id (FK)   |   |  city          |
+---------------+   |  base_price     |   +----------------+
                    |  final_price    |
                    |  overseas_flag  |
                    |  capped_flag    |
                    |  marquee_flag   |
                    +-----------------+

The seed_data.py script populates this schema in a single pass, performing fuzzy name matching between the Kaggle auction data and Cricsheet player names.

Pipeline Flow

Raw CSVs (Kaggle + Cricsheet)
        |
        v
seed_data.py  --->  ipl_valuation.db  --->  processed/auction_features.csv
                                                           |
                    01_data_merge.ipynb <------------------+
                           |
                    02_feature_engineering.ipynb
                           |
                    03_valuation_model.ipynb  --->  model_output.csv
                           |                        feature_importances.csv
                    04_insight_generation.ipynb -> franchise_efficiency.csv
                           |
              +------------+--------------------+
              v            v                    v
     ipl_dashboard.html  ipl_dashboard.pbit  valuation_sanity_check.xlsx
                                             ipl_recommendation.pptx

Feature Engineering

All features are computed with a strict anti-leakage constraint: only data from seasons strictly prior to the auction year is used. A player auctioned in 2022 can only have features derived from 2008-2021 performance.

Feature Categories

Category Features Notes
Career batting batting_avg, batting_sr, runs_career, boundary_pct Career aggregates to auction date
Career bowling bowling_avg, bowling_econ, wickets_career, dot_ball_pct Career aggregates to auction date
Recent form (batting) recent_batting_avg, recent_batting_sr Last 2 seasons only — highest predictive weight
Recent form (bowling) recent_bowling_econ, recent_wickets Last 2 seasons only
Context - batting powerplay_sr, death_sr, death_runs Phase-specific strike rates
Context - bowling powerplay_econ, death_econ, death_wickets Phase-specific economy rates
Player flags overseas_flag, capped_flag, captaincy_flag, marquee_flag Binary categorical signals
Experience ipl_seasons_prior, total_matches Number of prior IPL seasons played
Interaction experience_x_recent_sr, overseas_x_recent_sr Nonlinear combinations — captures the overseas scarcity effect

Players with no Cricsheet match (179 of 1,380 — first-timers or name mismatches) have performance features set to NaN and imputed using role-specific medians before modelling.


Model

Target Variable

log(1 + final_price_lakh) — log-transformation stabilises the right-skewed price distribution before fitting.

Algorithm

XGBoost Regressor with L1 + L2 regularisation. Hyperparameters tuned via time-aware cross-validation (not random/grid search, which would violate the temporal ordering constraint).

Validation Strategy — Walk-Forward CV

Standard k-fold CV is inappropriate for time-series auction data: if a model trained on 2022 data predicts 2018 prices, it has implicitly used future information.

Instead, walk-forward validation is used:

Fold 1:  Train 2013-2014  ->  Test 2015
Fold 2:  Train 2013-2015  ->  Test 2016
Fold 3:  Train 2013-2016  ->  Test 2017
...
Fold 11: Train 2013-2024  ->  Test 2025
Fold 12: Train 2013-2025  ->  Test 2026

This guarantees no future data ever enters the training window.

Baseline

A Ridge regression on 3 features (batting_sr, bowling_econ, overseas_flag) is computed for every fold. XGBoost must beat this baseline to be considered useful — it does, significantly, due to the nonlinear interactions between recent form, overseas status, and role.

Model Output

model_output.csv contains one row per sold player per auction season with:

  • actual_price_lakh — what the franchise actually paid
  • xgb_pred_lakh — XGBoost model's fair value estimate
  • residual_lakh — actual - predicted (positive = overpaid, negative = bargain)

Deliverables

1. Interactive HTML Dashboard — dashboard/ipl_dashboard.html

Open in any browser. No server or dependencies required — fully self-contained Plotly.

Page 1 — Auction Overview

  • Total spend by season (column chart)
  • Spend by player role (donut chart)
  • Price distribution by era: 2013-16 / 2017-20 / 2021-23 / 2024-26 (violin)
  • Base price vs final bid scatter (Indian vs Overseas)

Page 2 — Valuation Deep Dive

  • Actual vs XGBoost predicted price (walk-forward coloured by season)
  • Top 12 most overpaid players (actual > model)
  • Top 12 best bargains (actual < model)
  • XGBoost feature importances (top 15)

Page 3 — Franchise Efficiency

  • Total auction spend by franchise (all seasons)
  • Cumulative overpayment vs model fair value per franchise
  • Season-by-season overpayment heatmap

2. Power BI Template — dashboard/ipl_dashboard.pbit

Open in Power BI Desktop. The template automatically imports data from the processed CSVs using M queries.

Page Visuals
Auction Overview 5 KPI cards, column chart (spend/season), donut (spend/role), bar chart (spend/franchise), 2 slicers
Player Valuation 3 KPI cards, scatter (actual vs predicted), valuation detail table, season slicer
Franchise Efficiency Horizontal bar chart (overpayment), franchise efficiency table

DAX Measures defined in the template:

[Total Spend (Cr)]        = DIVIDE(SUMX(AuctionFeatures, AuctionFeatures[final_price_lakh]), 100)
[Players Bought]          = COUNTROWS(AuctionFeatures)
[Avg Price (L)]           = AVERAGEX(AuctionFeatures, AuctionFeatures[final_price_lakh])
[Max Price (L)]           = MAXX(AuctionFeatures, AuctionFeatures[final_price_lakh])
[Total Overpayment (L)]   = SUM(ModelOutput[residual_lakh])
[Model MAE (L)]           = AVERAGEX(ModelOutput, ABS(ModelOutput[residual_lakh]))
[Pct Overpaid]            = DIVIDE(CALCULATE(COUNTROWS(...), residual > 0), COUNTROWS(...))

If Power BI prompts for data source credentials, go to Transform Data -> Data Source Settings and verify the CSV paths point to data/processed/.


3. Excel Sanity-Check Workbook — excel/valuation_sanity_check.xlsx

A back-of-envelope analyst tool with 4 tabs:

Tab Contents
Raw Benchmarks Rs./Run and Rs./Wicket by season — the simplest market pricing reference
Back-of-Envelope Interactive formula: change yellow input cells, price updates automatically
Sensitivity Table Fair value matrix across batting runs x overseas premium assumptions
Model vs Manual Top residuals from XGBoost side-by-side with conditional formatting

4. Business Recommendation — deliverable/ipl_recommendation.pptx

A single 16:9 widescreen slide structured as a McKinsey-style one-pager:

  • Situation / Complication / Resolution — the business framing
  • 3 data-backed findings — with real numbers embedded from model_output.csv
  • 3 actionable recommendations — bid ceiling, overseas slot separation, form regression

Key Findings

1. Auction inflation is real — but driven by outlier seasons

Total IPL auction spend rose from ~Rs. 85 crore (2013) to ~Rs. 640 crore (2026). However, per-player inflation is concentrated in the top decile; the median price has risen far less. Mega-auction seasons (2018, 2022, 2025) account for a disproportionate share of total spend.

2. Overseas premium is overpriced

Overseas players command a statistically significant premium above their performance-implied value. The scarcity effect (maximum 4 overseas players per XI) is real but routinely overestimated in bidding wars. The premium is largest in mega-auction years when franchises are rebuilding full squads simultaneously.

3. Recent 2-season form dominates — but outlier seasons are overcorrected

XGBoost's highest-weight features are recent_batting_sr and recent_bowling_econ. The market correctly values recent form, but bids for career outlier seasons as if they will repeat — producing the largest positive residuals.

4. Death-over bowlers are systematically undervalued

Bowlers with strong death_econ (economy rate in overs 16-20) show consistently negative residuals — they are bought below model fair value. This represents the largest persistent inefficiency in the dataset.

5. Most overpaid player in the dataset

Rishabh Pant (2025) — actual bid: Rs. 27 crore / model fair value: ~Rs. 6 crore lower. The model does not price captaincy, franchise fan-base value, or media narrative — it prices only ball-by-ball performance. The gap is the conversation.


Setup & Reproduction

Prerequisites

Python 3.10+
Anaconda (recommended) or pip
Power BI Desktop (for .pbit)
Microsoft Excel / LibreOffice (for .xlsx)

Install dependencies

pip install -r requirements.txt

requirements.txt covers: pandas, numpy, scikit-learn, xgboost, plotly, openpyxl, python-pptx, fuzzywuzzy, python-Levenshtein, sqlite3 (stdlib).

Download raw data

Place the following files in data/raw/ before running the pipeline:

File / Folder Source
data/raw/auction_sunny/IPL_Auction/ sunnyyadav754 Kaggle dataset — extract the ZIP, keep the per-year CSV structure
data/raw/ball_by_ball_ipl.csv jamiewelsh2 Kaggle dataset

Run the pipeline

# 1. Seed the database and build the feature matrix
python data/seed_data.py

# 2. Execute notebooks in order
jupyter nbconvert --to notebook --execute --inplace notebooks/01_data_merge.ipynb
jupyter nbconvert --to notebook --execute --inplace notebooks/02_feature_engineering.ipynb
jupyter nbconvert --to notebook --execute --inplace notebooks/03_valuation_model.ipynb
jupyter nbconvert --to notebook --execute --inplace notebooks/04_insight_generation.ipynb

# 3. Generate deliverables
python dashboard/generate_dashboard.py     # -> dashboard/ipl_dashboard.html
python dashboard/generate_powerbi.py       # -> dashboard/ipl_dashboard.pbit
python excel/generate_excel.py             # -> excel/valuation_sanity_check.xlsx
python deliverable/generate_pptx.py        # -> deliverable/ipl_recommendation.pptx

Total runtime: approximately 3-5 minutes on a standard laptop (dominated by XGBoost walk-forward training in notebook 03).


Design Decisions & Methodology Notes

Why not use career totals as the primary feature?

Career totals conflate early-career low-quality seasons with recent high-quality form. A player who scored 3,000 runs over 10 seasons is priced very differently from one who scored 3,000 runs in the last 3. The 2-season rolling window captures this distinction.

Why XGBoost over linear regression?

The relationship between overseas status and recent form is nonlinear. A domestic player with a recent SR of 160 and an overseas player with the same SR are priced very differently. XGBoost captures this interaction; a linear model cannot without manual feature engineering. Both are run — XGBoost consistently beats Ridge on MAE across all walk-forward folds.

Why log-transform the target?

Raw prices are highly right-skewed (a few mega-contracts dominate). Modelling log(1 + price) stabilises variance and prevents the model from over-fitting to outlier transactions. Predictions are exponentiated back before computing residuals.

Why is the 2013 dataset different?

The 2013 auction data uses USD prices (pre-IPL becoming a fully rupee-denominated competition). A fixed conversion rate of Rs. 55/USD is applied. This introduces a small approximation but affects fewer than 60 records.

What the model does NOT capture

  • Captaincy value — leading a franchise has brand/sponsorship value beyond runs and wickets
  • Injury risk — no injury history is available in the source data
  • Fan sentiment — marquee player flags are included as binary dummies, but the magnitude of fan premium is not modelled
  • Franchise retention rules — RTM (Right to Match) cards distort the auction price signal; retained players are excluded from the dataset

These omissions are documented features of the model, not oversights. The residual for a player is best interpreted as: "how much more/less than pure performance value did this franchise pay?"


Acknowledgements

  • sunnyyadav754 — IPL auction dataset (Kaggle)
  • jamiewelsh2 — Ball-by-ball IPL dataset (Kaggle / Cricsheet)
  • Cricsheet.org — Original ball-by-ball data source

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages