0% found this document useful (0 votes)
4 views21 pages

IPL Code Explanation

This document serves as a beginner's guide to analyzing IPL match data using Python, detailing libraries, functions, and methods utilized in the analysis. It covers data loading, cleaning, and various analytical techniques, including grouping, aggregation, and visualization. The document also includes cricket-specific metrics and formulas to derive insights from the dataset.

Uploaded by

u.kulshrestha
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
4 views21 pages

IPL Code Explanation

This document serves as a beginner's guide to analyzing IPL match data using Python, detailing libraries, functions, and methods utilized in the analysis. It covers data loading, cleaning, and various analytical techniques, including grouping, aggregation, and visualization. The document also includes cricket-specific metrics and formulas to derive insights from the dataset.

Uploaded by

u.kulshrestha
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd

IPL Dataset Analysis

A Complete Beginner's Guide to the Code


Group 9 | DSUP Project

What is this document?


This document explains every library, function, method, formula, and operator used in the IPL
Jupyter Notebook — written in simple, beginner-friendly language. Each concept is explained
with what it does, why it was used, and a code example.
1. Project Overview
This project analyzes ball-by-ball IPL (Indian Premier League) match data across multiple
seasons. The goal is to discover insights about players, teams, and how the game has evolved
over time using Python and data visualization tools.

The dataset contains columns like: batter, bowler, runs scored, wicket type, match ID, season,
venue, toss winner, and more — one row per ball bowled.
2. Libraries Used
Libraries are pre-written collections of code that give you powerful tools without writing
everything from scratch. Think of them like apps you install to get extra features.

2.1 pandas (imported as pd)


pandas is the most important library in this project. It lets you work with data in a table format
called a DataFrame — similar to Excel but inside Python.

Key things pandas lets you do:


• Load Excel/CSV files into Python
• Filter, sort, and group rows
• Calculate sums, averages, counts
• Merge tables together (like VLOOKUP)
• Clean messy or missing data

import pandas as pd
df = pd.read_excel("[Link]") # Load the Excel file

2.2 [Link] (imported as plt)


matplotlib is the drawing tool. It creates charts and graphs. You describe what you want (bar
chart, line chart, etc.), and it draws it. [Link]() at the end actually displays the chart.

import [Link] as plt


[Link]([1,2,3], [10,20,30]) # Draw a line
[Link]() # Display it

2.3 seaborn (imported as sns)


seaborn is built on top of matplotlib. It produces prettier, more styled charts with less code. It's
especially good for heatmaps and grouped bar charts. Used heavily for visualizations in this
project.

import seaborn as sns


[Link](x=..., y=...) # Styled bar chart
[Link](data) # Heatmap
2.4 numpy (imported as np)
numpy is a math library for working with numbers and arrays (lists of numbers). In this project
it's used in the Impact Index section to handle number scaling. Most of the time pandas handles
the math, and numpy works behind the scenes.

import numpy as np

2.5 [Link]
From the scikit-learn machine learning library. A Scaler is a tool that takes numbers of different
ranges (e.g., runs in thousands vs economy around 7-9) and rescales them all to a 0-to-1 range
so they can be fairly compared and combined into one score.

Formula it uses: (value - minimum) / (maximum - minimum)

from [Link] import MinMaxScaler


scaler = MinMaxScaler()
scaled = scaler.fit_transform(data)
3. Loading & Exploring the Data
3.1 pd.read_excel()
Reads an Excel file (.xlsx) and converts it into a pandas DataFrame stored in a variable called
df. Everything after this uses df to access the data.
df = pd.read_excel("[Link]")

3.2 [Link]() and [Link]()


head() shows the first 5 rows (or however many you specify). tail() shows the last rows. Used
constantly to quickly peek at what the data looks like without printing everything.
[Link]() # First 5 rows
[Link](10) # First 10 rows
[Link]() # Last 5 rows

3.3 [Link]
Returns a tuple of (number of rows, number of columns). Tells you how big the dataset is at a
glance.
[Link] # Example output: (250000, 22)

3.4 [Link]
Returns a list of all column names in the DataFrame. Useful to see what data is available.
[Link] # Index of column names

3.5 [Link]
Shows the data type of every column — integer, float (decimal), object (text), datetime, etc.
Important because some operations only work on specific types.
[Link] # e.g., runs_batter: int64, batter: object

3.6 [Link]()
Gives a full summary: column names, their data types, and how many non-null (non-empty)
values each has. Great for spotting missing data.
[Link]()
3.7 [Link]()
Calculates summary statistics for all numeric columns: count, mean (average), min, max, and
percentiles (25%, 50%, 75%). [Link](include='all') extends this to text columns too
(showing top value, frequency, etc.).
[Link]() # Numeric columns only
[Link](include='all') # All columns
4. Data Cleaning
Raw data is rarely perfect. This section covers every cleaning step done to make the dataset
accurate and usable.

4.1 Dropping Unnamed Columns


Excel files often export with extra empty columns named 'Unnamed: 0', 'Unnamed: 1', etc. The
code finds all columns whose names contain the word 'unnamed' and drops them.
[Link]([Link][[Link]('unnamed', case=False)],
axis=1, inplace=True)

Breaking it down:
• [Link]('unnamed', case=False) — checks each column name if it
contains 'unnamed' (case-insensitive), returns True/False for each
• [Link][...] — uses that True/False to select only the column names that matched
• [Link](..., axis=1) — drops those columns (axis=1 means columns; axis=0 means rows)
• inplace=True — modifies df directly instead of creating a new copy

4.2 Fixing Unknown Match Winners (.loc[])


Some matches ended in a Super Over (a tiebreaker). The match_won_by column had
'Unknown' for these. The real winner was in another column called superover_winner.
[Link][df['match_won_by'] == 'Unknown', 'match_won_by'] =
df['superover_winner']

.loc[] is one of the most important pandas tools. It selects specific rows and columns for reading
or writing.
Syntax: [Link][row_condition, column_name]
• df['match_won_by'] == 'Unknown' — creates a True/False list: True for every row where
match_won_by is 'Unknown'
• [Link][True/False list, 'match_won_by'] — go to only the True rows, in the match_won_by
column
• = df['superover_winner'] — replace those cells with values from superover_winner

4.3 Fixing Team Names (.replace() with dictionary)


Teams like Delhi Daredevils were renamed to Delhi Capitals. The old names appear in multiple
columns. A dictionary maps old names to new names, and .replace() swaps them everywhere.
team_name_corrections = {
'Delhi Daredevils': 'Delhi Capitals',
'Kings XI Punjab': 'Punjab Kings',
'Royal Challengers Bangalore': 'Royal Challengers Bengaluru',
'Rising Pune Supergiant': 'Rising Pune Supergiants'
}
for col in ['batting_team', 'bowling_team', 'match_won_by', ...]:
df[col] = df[col].replace(team_name_corrections)

The for loop saves repeating the same line 5 times — it loops through each column name in the
list and applies the replacement.

4.4 Fixing Season Formats (.apply() with custom function)


Some seasons were stored as strings like '2007/08'. Python can't sort or plot these correctly. A
custom function converts them all into proper integers.
def fix_season(x):
if x == '2020/21':
return 2020
elif '/' in x:
return int('20' + [Link]('/')[-1])
else:
return int(x)

df['season'] = df['season'].astype(str).apply(fix_season)

Key concepts here:


• .astype(str) — converts the season column to text type first so we can check for '/'
characters inside
• .apply(fix_season) — runs the fix_season function on every single value in the column,
one by one
• [Link]('/')[-1] — splits '2007/08' into ['2007', '08'] and takes the last item '08'
• int('20' + '08') — joins '20' and '08' to get '2008', then converts to integer 2008

4.5 .fillna() — Filling Empty Cells


When combining datasets, some cells may be empty (NaN = Not a Number). .fillna(0) replaces
all NaN values with 0 so calculations don't fail.
team_stats = [Link]({...}).fillna(0)
5. Analysis Functions & Methods
5.1 .groupby() — Grouping Data
groupby() is like pivot tables in Excel. It groups all rows that share the same value in a column,
then lets you calculate something per group.
[Link]('batter')['runs_batter'].sum()

Steps: 1) Make a group per unique batter name. 2) Look at only the runs_batter column. 3) Add
up all values in each group.

You can group by multiple columns too:


[Link](['season', 'match_id'])['runs_total'].sum()
This groups by season AND match_id together — so you get total runs per match per season.

5.2 .agg() — Multiple Calculations at Once


.agg() (aggregate) lets you apply different calculations to different columns in one step after a
groupby.
bat = [Link]('batter').agg({
'runs_batter': 'sum', # total runs
'ball': 'count' # balls faced
})

Available aggregation options: 'sum', 'mean', 'count', 'min', 'max', 'nunique', 'std'

5.3 .reset_index() — Restoring Columns


After groupby(), the grouped column becomes the 'index' (row label) instead of a normal
column. .reset_index() converts it back into a regular column so it's easier to work with.
season_runs = [Link](['season','match_id'])
['runs_total'].sum().reset_index()
Without reset_index, season and match_id would be stuck as index labels and harder to filter or
plot.

5.4 .drop_duplicates() — Removing Repeated Rows


Since the dataset is ball-by-ball, each match appears hundreds of times. For match-level info
(like who won), we only need one row per match. .drop_duplicates() keeps only the first
occurrence of each duplicate row.
df[['match_id','match_won_by']].drop_duplicates()
5.5 .nunique() — Count Unique Values
Counts how many distinct unique values exist in a column. If match_id '101' appears 300 times
(300 balls), it's still counted as 1.
df['match_id'].nunique() # Total unique matches
df['batter'].nunique() # Total unique players

5.6 .notna() and .isna()


.notna() returns True where a cell has a value (not empty). .isna() returns True where a cell is
empty/null. Used to filter rows based on whether data exists.
df['wicket_kind'].notna().sum() # Count all wickets
Why this works: .notna() creates a True/False column. .sum() adds them up (True=1, False=0)
to count how many wickets fell.

5.7 .value_counts() — Frequency Count


Counts how many times each unique value appears in a column, sorted highest to lowest.
df['bowler'][df['wicket_kind'].notna()].value_counts().head(10)
Step by step: Filter to wicket rows only → get the bowler column → count how many times each
bowler appears (= wickets taken) → show top 10.

5.8 .sort_values() — Sorting


Sorts a DataFrame or Series by values in a column.
bat.sort_values('strike_rate', ascending=False).head(10)
• ascending=False — highest first (descending order)
• ascending=True — lowest first

5.9 .merge() — Joining Two Tables


Combines two DataFrames based on a shared column — like Excel VLOOKUP or SQL JOIN.
merged = [Link](first_innings, second_innings, on='match_id',
suffixes=('_first','_second'))

Parameters:
• on='match_id' — the column to match rows on
• suffixes — when both tables have a column with the same name, add these suffixes to
tell them apart
• how='inner' (default) — only rows found in BOTH tables
• how='left' — all rows from left table, matched or not
5.10 .unstack() — Pivot for Heatmaps
After grouping by two columns, unstack() 'pivots' one level into columns, creating a matrix (rows
vs columns grid) that's perfect for heatmaps.
team_season_wins =
wins_data.groupby(['match_won_by','season']).size().unstack(fill_value=0
)
Result: rows = teams, columns = seasons, values = win counts. This matrix shape is exactly
what seaborn's heatmap expects.

5.11 .size() vs .count()


.size() counts all rows in a group including empty ones. .count() skips empty (NaN) cells.
Use .size() when counting occurrences, .count() when counting valid values.
real_wickets.groupby(['season','match_id']).size() # Wickets per match

5.12 .mean() — Average


Calculates the average of a column. Has a clever trick when used on True/False columns —
since True=1 and False=0, .mean() gives you the proportion of True values.
merged['chase_win'].mean() * 100 # % of matches chasing team won

5.13 .idxmax() — Find Index of Maximum Value


Returns the row index (position) of the maximum value. Used here to find the top scorer per
season.
season_runs.loc[season_runs.groupby('season')['runs_batter'].idxmax()]
Step by step: For each season, find the row number of the highest runs. Then use .loc[] to
retrieve those actual rows. Result: top batter per season.

5.14 .isin() — Check Against a List


Checks if each value in a column is inside a given list. Returns True/False per row.
~df['wicket_kind'].isin(['run out', 'retired hurt', 'obstructing the
field'])
The ~ in front flips True to False and False to True (this is the NOT operator). So this line
means: keep rows where wicket type is NOT any of those three — because those dismissals
don't count for the bowler.
6. Cricket Formulas Used

Metric Formula / Code What it means


Strike Rate bat['strike_rate'] = (runs / Runs scored per 100 balls. Higher =
balls) * 100 more aggressive batter.
Economy Rate bowl['economy'] = Runs given per over. Lower = more
runs_conceded / overs economical bowler.
Overs overs = balls / 6 Converts ball count to overs (6 balls =
1 over).
Win/Loss Ratio wins / losses Wins per each loss. 1.2 means 1.2
wins for every loss.
Chasing Win % chase_win.mean() * 100 % of matches won by the team
batting second.
Toss-to-Win % toss_win_match.mean() * 100 % of times winning the toss led to
winning the match.
7. Operators & Special Syntax

7.1 ~ (Tilde) — NOT Operator


Flips True to False and False to True. Used to reverse a filter condition.
~df['wicket_kind'].isin([...]) # Keep rows where it is NOT in the list

7.2 & and | — AND / OR for Filters


Used to combine multiple filter conditions. Each condition MUST be wrapped in parentheses.
df[df['wicket_kind'].notna() & ~df['wicket_kind'].isin([...])]
• & means AND — both conditions must be True
• | means OR — either condition can be True

7.3 == — Equality Check


Checks if a value equals something. Returns True or False for every row.
df['match_won_by'] == 'Unknown' # True for rows with 'Unknown'

7.4 .iloc[] vs .loc[]


.loc[] selects by label (column name or condition). .iloc[] selects by integer position (row number
0, 1, 2...).
[Link][df['season'] == 2023] # rows where season is 2023
[Link][0] # first row by position
top_run_season['runs_batter'].iloc[i] # value at position i in loop

7.5 if col in [Link]:


Checks if a column name actually exists in the DataFrame before using it. Prevents errors if a
column is missing from the data.
if col in [Link]:
df[col] = df[col].replace(team_name_corrections)
8. Charts & Visualizations

8.1 Chart Setup Functions


These lines appear in almost every chart block:
[Link](figsize=(10, 6)) # Create blank canvas, width x height in
inches
[Link]('Chart Title') # Add a title
[Link]('X Axis Label') # Label the x-axis
[Link]('Y Axis Label') # Label the y-axis
[Link](rotation=45) # Rotate x-axis labels 45 degrees to avoid
overlap
plt.tight_layout() # Auto-adjust spacing so nothing gets cut
off
[Link](alpha=0.3) # Add faint grid lines (alpha =
transparency 0-1)
[Link]() # Display the chart

8.2 Bar Charts ([Link])


Used for: Win/Loss Ratio, Top scorer per season, Wicket taker per season, Most titles.
[Link](x=team_stats['win_loss_ratio'], y=team_stats.index)
Horizontal bar chart: x = the values, y = the labels. Seaborn automatically colors and styles it.

8.3 Heatmaps ([Link])


Used for: Toss win%, Team vs Season wins, Season champions. A heatmap shows values as
colors in a grid — darker = higher value.
[Link](team_season_wins, annot=True, cmap='YlOrRd')
• annot=True — writes the actual number inside each cell
• cmap='YlOrRd' — color scheme (Yellow→Orange→Red)
• cmap='Blues' — Blue shades (used for champion heatmap)
• cmap='coolwarm' — Blue (low) to Red (high)
• cbar=False — hides the color scale bar on the side

8.4 Line Charts ([Link])


Used for: Average runs per season, Average wickets per season. Shows how a value changes
over time.
[Link](season_avg_runs['season'], season_avg_runs['runs_total'],
marker='o')
marker='o' adds a dot at each data point so individual seasons are easy to see.

8.5 Adding Text Labels on Bars ([Link])


In the Top Scorer and Top Wicket Taker charts, player names are written vertically on top of
each bar.
ax = [Link](x='season', y='runs_batter', data=top_run_season)
for i in range(len(top_run_season)):
[Link](
i, # x position (bar number)
top_run_season['runs_batter'].iloc[i], # y position (top of
bar)
top_run_season['batter'].iloc[i], # text (player name)
ha='center', # horizontal alignment
va='bottom', # vertical alignment
rotation=90, # vertical text
fontsize=8 # small font
)

This loop runs once for each bar (i = 0, 1, 2...) and writes the name at the correct position on
each bar.
9. AI-Driven Impact Index
This was the most advanced part of the notebook. It creates a combined 'impact score' for
players across batting and bowling. Here is how it works step by step:

Step 1 — Calculate Batting Stats per Player


batting = [Link]('batter').agg(
runs=('runs_batter', 'sum'),
balls=('valid_ball', 'sum'),
innings=('match_id', 'nunique')
).reset_index()
batting['strike_rate'] = (batting['runs'] / batting['balls'] *
100).round(2)
batting = batting[batting['balls'] >= 200] # Only players with 200+
balls

.round(2) rounds the number to 2 decimal places.


The minimum ball filter (200+) removes players with tiny samples — otherwise someone who hit
one six in one ball would have a 600 strike rate.

Step 2 — Calculate Bowling Stats per Player


Runs out, retired hurt, and obstructing the field are excluded because those aren't credited to
the bowler. Only actual bowling wickets count.
bowling_df = df[df['wicket_kind'].notna() &
~df['wicket_kind'].isin(['run out', 'retired hurt',
'obstructing the field'])]

Step 3 — Normalize with MinMaxScaler


Runs can be in thousands. Economy is around 7-9. You can't add 5000 and 7.2 and call it a fair
score. MinMaxScaler converts everything to 0-1 range.
from [Link] import MinMaxScaler
scaler = MinMaxScaler()
scaled = scaler.fit_transform(data)

Formula: (value - minimum) / (maximum - minimum)


So the player with the most runs gets 1.0, the player with the fewest gets 0.0, and everyone else
falls proportionally in between.
Step 4 — Combine into One Score
Batting score and bowling score are merged for each player and added into a single 'impact'
number. Players who do well in both batting and bowling rank highest.
10. Quick Reference: All Methods at a Glance

Method / Function What it does (in plain English)


pd.read_excel() Loads an Excel file into a DataFrame
.head() / .tail() Shows first or last N rows
.shape Returns (rows, columns) count
.dtypes Shows data type of each column
.info() Full summary: columns, types, non-null counts
.describe() Summary statistics: min, max, mean, percentiles
.loc[] Select rows/columns using labels or conditions
.iloc[] Select rows/columns using integer position numbers
.groupby() Group rows by a column, then calculate per group
.agg() Apply multiple calculations in one step after groupby
.reset_index() Convert index back into a normal column
.drop_duplicates() Remove repeated/duplicate rows
.nunique() Count unique distinct values in a column
.notna() / .isna() True where cell has data / True where cell is empty
.value_counts() Count occurrences of each unique value, sorted
.sort_values() Sort DataFrame by column values
.fillna() Replace empty (NaN) cells with a specified value
.replace() Replace specific values with new ones
.astype() Convert a column to a different data type
.apply() Run a custom function on every value in a column
[Link]() Join two DataFrames by a shared column
.unstack() Pivot one level of grouped data into columns (for heatmaps)
.size() Count rows per group (including NaN)
.mean() Calculate average; on True/False gives proportion
.idxmax() Return index of the maximum value
.isin() Check if values exist in a given list
.drop() Remove columns or rows
.round() Round numbers to N decimal places
~ NOT operator — flips True/False
& / | AND / OR for combining filter conditions
MinMaxScaler Rescales numbers to 0-1 range for fair comparison
11. All Charts in the Notebook

Chart Type What it shows


Win/Loss Ratio by Team Horizontal Bar Which team wins most relative to losses
Average Score by Stadium Horizontal Bar Which venues produce high-scoring matches
Toss Win % → Match Win % Heatmap Does winning the toss help win the match?
Average Runs per Season Line Chart How scoring has evolved over IPL seasons
Average Wickets per Season Line Chart How dismissals trend across seasons
Team vs Season Wins Heatmap How many wins each team had per season
Chasing vs Defending Bar Chart Who wins more — team batting 1st or 2nd?
Top Run Scorer per Season Bar + Labels Best batter each season with their name
Top Wicket Taker per Bar + Labels Best bowler each season with their name
Season
Season Champions Grid Heatmap Which team won the title each year (1 =
champion)
Most IPL Titles Bar Chart Teams with the most total title wins
12. Summary
This notebook is a complete end-to-end data analysis project. Here is the overall flow:

• Load — Read the Excel file into pandas


• Explore — Understand the shape, columns, and data types
• Clean — Remove junk columns, fix unknown values, standardize team names, fix
season formats
• Analyze — Use groupby, agg, merge, and custom formulas to extract insights
• Visualize — Use matplotlib and seaborn to create charts that make patterns visible
• Score — Build an Impact Index using machine learning's MinMaxScaler to fairly rank
players

Every function, operator, and method in this notebook was explained in this document — from
the simple ones like .head() all the way to advanced ones like .idxmax(), .unstack(), and
MinMaxScaler.

— End of Document —

You might also like