ipl-analytics / src /clean.py
anshumanSingh-tech
Update dataset with complete IPL 2026 season, fix dashboard bugs, improve ML features
1c7a005
Raw
History Blame Contribute Delete
6.37 kB
import pandas as pd
import numpy as np
from pathlib import Path
RAW = Path("E:/ipl-analytics/data/raw")
PROCESSED = Path("E:/ipl-analytics/data/processed")
PROCESSED.mkdir(parents=True, exist_ok=True)
TEAM_NAME_MAP = {
"Rising Pune Supergiant" : "Rising Pune Supergiants",
"King XI Punjab" : "Punjab Kings",
"Pune Warriors" : "Pune Warriors India",
"Deccan Chargrers" : "Sunrisers Hyderabad",
"Delhi Daredevils" : "Delhi Capitals",
"Royal Challengers Bengaluru" : "Royal Challengers Bangalore",
}
VENUE_KEYWORDS = {
"Wankhede": "Wankhede Stadium",
"Chinnaswamy": "M Chinnaswamy Stadium",
"Chidambaram": "MA Chidambaram Stadium",
"Chepauk": "MA Chidambaram Stadium",
"Eden Gardens": "Eden Gardens",
"Arun Jaitley": "Feroz Shah Kotla",
"Feroz Shah Kotla": "Feroz Shah Kotla",
"Rajasekhara": "Vizag Stadium",
"Yadavindra": "Mullanpur Stadium",
"Ekana": "Ekana Stadium",
"Rajiv Gandhi": "Uppal Stadium",
"IS Bindra": "PCA Stadium",
"Mohali": "PCA Stadium",
"Narendra Modi": "Motera Stadium",
"Dy Patil": "DY Patil Stadium",
"Brabourne": "Brabourne Stadium",
}
IPL_VALID_SEASONS = set(range(2008, 2025))
import datetime
IPL_VALID_SEASONS = set(range(2008, datetime.date.today().year + 1))
SLASH_SEASON_MAP = {
"2007/08" : 2008,
"2009/10" : 2010,
"2020/21" : 2020,
}
def clean_matches(matches: pd.DataFrame) -> pd.DataFrame:
df = matches.copy()
if "id" in df.columns:
df = df.rename(columns={"id": "match_id"})
df["date"] = pd.to_datetime(df["date"], errors="coerce")
def fix_season(val):
val = str(val).strip()
if val in SLASH_SEASON_MAP:
return SLASH_SEASON_MAP[val]
if "/" in val:
parts = val.split("/")
suffix = parts[1].strip()
prefix = parts[0].strip()[:2]
return int(prefix + suffix)
val_clean = val.replace("IPL", "").replace("Season", "").strip()
year = int(float(val_clean))
if year == 2007:
return 2008
return year
df["season"] = df["season"].apply(fix_season).astype("int32")
detected = set(df["season"].unique())
unexpected = detected - IPL_VALID_SEASONS
missing = IPL_VALID_SEASONS - detected
if unexpected:
print(f"WARNING β€” unexpected seasons found : {sorted(unexpected)}")
print(f" Dropping {len(df[df['season'].isin(unexpected)])} rows.")
df = df[df["season"].isin(IPL_VALID_SEASONS)].copy()
else:
print("OK β€” all seasons are valid IPL years.")
if missing:
print(f"INFO β€” seasons not in dataset : {sorted(missing)}")
print(f" Expected if your CSV doesn't cover those years yet.")
else:
print("OK β€” all expected IPL seasons are present.")
print(f"\nSeason distribution : {sorted(df['season'].unique())}")
print(f"Season range : {df['season'].min()} – {df['season'].max()}")
print(f"Total seasons : {df['season'].nunique()}")
print(f"Total matches : {len(df)}")
df["venue"] = df["venue"].astype(str).str.strip()
for keyword, clean_name in VENUE_KEYWORDS.items():
mask = df["venue"].str.contains(keyword, case=False, na=False)
df.loc[mask, "venue"] = clean_name
for col in ["result_margin", "dl_applied", "target_runs"]:
if col in df.columns:
df[col] = pd.to_numeric(df[col], errors="coerce").fillna(0).astype(int)
for col in ["team1", "team2", "winner", "toss_winner"]:
if col in df.columns:
df[col] = df[col].replace(TEAM_NAME_MAP)
df["player_of_match"] = df["player_of_match"].fillna("N/A")
def result_type(row):
r = str(row.get("result", "")).lower().strip()
if r == "runs": return "runs"
if r == "wickets": return "wickets"
return "no_result"
df["result_type"] = df.apply(result_type, axis=1)
df["is_no_result"] = df["winner"].isna().astype(int)
df["winner"] = df["winner"].fillna("No Result")
df["day_of_week"] = df["date"].dt.day_name()
df["month"] = df["date"].dt.month
df = df.sort_values(["season", "date"]).reset_index(drop=True)
print(f"\nclean_matches done: {matches.shape} β†’ {df.shape}")
remaining_nulls = df.isnull().sum()
remaining_nulls = remaining_nulls[remaining_nulls > 0]
if len(remaining_nulls):
print(f"Remaining nulls:\n{remaining_nulls.to_string()}")
else:
print("No nulls remaining.")
return df
def clean_deliveries(deliveries: pd.DataFrame) -> pd.DataFrame:
df = deliveries.copy()
df = df.rename(columns={
"batter": "batsman",
})
for col in ["batting_team", "bowling_team"]:
if col in df.columns:
df[col] = df[col].replace(TEAM_NAME_MAP)
num_cols = ["inning", "over", "ball", "batsman_runs", "extra_runs", "total_runs"]
for col in num_cols:
if col in df.columns:
df[col] = pd.to_numeric(df[col], errors="coerce").fillna(0).astype(int)
df["is_wide"] = (df["extras_type"] == "wides").astype(int)
df["is_noball"] = (df["extras_type"] == "noballs").astype(int)
for col in ["batting_team", "bowling_team"]:
df[col] = df[col].replace(TEAM_NAME_MAP)
df["player_dismissed"] = df["player_dismissed"].fillna("not_out")
df["dismissal_kind"] = df["dismissal_kind"].fillna("not_out")
df["is_wicket"] = df["is_wicket"].fillna(0).astype(int)
df["is_four"] = (df["batsman_runs"] == 4).astype(int)
df["is_six"] = (df["batsman_runs"] == 6).astype(int)
df["is_dot_ball"] = (
(df["batsman_runs"] == 0) &
(df["is_wide"] == 0) &
(df["is_noball"] == 0)
).astype(int)
def over_phase(over):
if over <= 6: return "powerplay"
if over <= 15: return "middle"
return "death"
df["over_phase"] = df["over"].apply(over_phase)
df["is_legal_delivery"] = ((df["is_wide"] == 0) & (df["is_noball"] == 0)).astype(int)
df = df.sort_values(["match_id", "inning", "over", "ball"]).reset_index(drop=True)
print(f"\nclean_deliveries: {deliveries.shape} β†’ {df.shape}")
print(f" Nulls remaining:\n{df.isnull().sum()[df.isnull().sum()>0].to_string()}")
return df