This Data Dive explores hypothesis testing IPL Player Performance Dataset by doing A/B Testing.
Hypothesis 1: using Neyman–Pearson framework
Hypothesis 2: using Fisher’s Significance Testing framework
ipl_raw<-read_csv("C:/mayangup/SP26/ipl-data_Dataset 1.csv")
## Rows: 24044 Columns: 22
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (5): player, team, match_outcome, opposition_team, venue
## dbl (16): match_id, runs, balls_faced, fours, sixes, wickets, overs_bowled,...
## date (1): date
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Note: Data Preparation: The data set includes only 5 matches of year 2025 that is not complete and this would distort all calculations, so to avoid this, filtered out all rows from 2025 and used a clean dataset for further analysis including complete seasons only.
IPL <- ipl_raw |>
mutate(
date = as.Date(date),
season = year(date)
) |>
filter(season < 2025)
We test whether batting strike rate differs between innings in matches that were won versus lost, using a two‑sample comparison of means under the Neyman–Pearson framework.
Main variable: strike_rate
Group A: Innings from matches the team won
Group B: Innings from matches the team lost
Null Hypothesis (H₀): The mean strike rate in wins is equal to the mean strike rate in losses.
\[ \LARGE \mu_{\text{SR,win}} = \mu_{\text{SR,loss}} \]
Alternative Hypothesis (H₁): The mean strike rate in wins differs from the mean strike rate in losses.
\[ \LARGE \mu_{\text{SR,win}} \neq \mu_{\text{SR,loss}} \]
Type I error rate (α): \((\alpha = 0.05)\) A 5% risk of falsely detecting that mean strike rate differs between wins and losses when it actually does not.
Power and Type II error (β): Target power of \((1 - \beta = 0.80)\), corresponding to \((\beta = 0.20)\). This means a 20% chance of failing to detect a true difference in mean strike rate which is standard in many applied settings.
Minimum effect size (Cohen’s d): A medium effect size, \((d = 0.5)\), as the smallest difference in strike rate that is practically meaningful in changing the match outcomes.
# Neyman–Pearson design choices
alpha_level <- 0.05
power_target <- 0.80
effect_size <- 0.5
# Required sample size per group for a two-sample t-test
np_power_calc <- pwr.t.test(
d = effect_size,
sig.level = alpha_level,
power = power_target,
type = "two.sample",
alternative = "two.sided"
)
np_power_calc
##
## Two-sample t test power calculation
##
## n = 63.76561
## d = 0.5
## sig.level = 0.05
## power = 0.8
## alternative = two.sided
##
## NOTE: n is number in *each* group
The Neyman–Pearson power analysis indicated that approximately 64 observations per group are required to detect a medium effect size \((Cohen’s\ d = 0.5)\) with \(α =0.05\) and \(power = 0.80\).
IPL_np <- IPL |>
mutate(
win_binary = ifelse(match_outcome == "win", 1, 0)
)
n_win <- sum(IPL_np$win_binary == 1, na.rm = TRUE)
n_loss <- sum(IPL_np$win_binary == 0, na.rm = TRUE)
n_win
## [1] 11633
n_loss
## [1] 12292
The above test shows that IPL dataset contains 11,633 innings from matches that were won and 12,292 innings from matches that were lost, which far exceeds the required sample size. Thus, dataset provides more than sufficient statistical power to conduct a two-sample comparison of mean strike rate under the Neyman–Pearson framework.
mean_win <- mean(IPL_np$strike_rate[IPL_np$win_binary == 1], na.rm = TRUE)
mean_loss <- mean(IPL_np$strike_rate[IPL_np$win_binary == 0], na.rm = TRUE)
mean_win
## [1] 72.94127
mean_loss
## [1] 77.73649
t_test_np <- t.test(strike_rate ~ win_binary,
data = IPL_np,
alternative = "two.sided"
)
t_test_np
##
## Welch Two Sample t-test
##
## data: strike_rate by win_binary
## t = 4.9481, df = 22816, p-value = 7.549e-07
## alternative hypothesis: true difference in means between group 0 and group 1 is not equal to 0
## 95 percent confidence interval:
## 2.895699 6.694737
## sample estimates:
## mean in group 0 mean in group 1
## 77.73649 72.94127
cohen_d_np <- cohen.d(
IPL_np$strike_rate,
IPL_np$win_binary,
)
cohen_d_np
##
## Cohen's d
##
## d estimate: 1.419914 (large)
## 95 percent confidence interval:
## lower upper
## 1.399863 1.439966
A small effect is around \(d = 0.2\).
A medium effect is around \(d = 0.5\).
A large effect is around \(d = 0.8\).
Here , Cohen’s d estimate is \(d=1.42 (large)\) which is well above the 0.8 threshold, This indicates that the difference in strike rate between wins and losses represents a very large and practically meaningful effect.
The two‑sample t‑test provides strong evidence that mean strike rate differs between winning and losing innings.
Losing innings show a higher average strike rate \((77.74)\) than winning innings \((72.94)\), and this difference of about 4.8 runs per 100 balls is statistically significant.
\(t(22,816) = 4.95, p < 0.001\) , the observed difference in mean strike rate is statistically significant and extremely unlikely to be due to chance.
The 95% confidence interval for the difference \([2.90,\ 6.69]\) excludes zero, indicating that the effect is unlikely to be due to chance.
Cohen’s d is approximately \(1.42\), which is well above the 0.8 threshold for a large effect, showing that the difference is not only statistically detectable but also substantial in magnitude.
Conclusion :-
Under the Neyman–Pearson framework with \(\alpha = 0.05\), we reject the null hypothesis and conclude that strike rate differs meaningfully between wins and losses.
ggplot(data = IPL_np) +
geom_boxplot(
aes(x = factor(win_binary, labels = c("Loss", "Win")),
y = strike_rate,
fill = factor(win_binary)),
alpha = 0.7,
outlier.alpha = 0.2
) +
scale_fill_manual(
values = c("orangered", "steelblue"),
name = "Match Outcome",
labels = c("Loss", "Win")
) +
labs(
title = "Strike Rate Distribution for Wins vs Losses",
x = "Match Outcome",
y = "Strike Rate"
) +
theme_minimal(base_size = 13) +
theme(legend.position = "none")
The Boxplot shows that the median strike rate is higher in losses than in wins, indicating that losing innings typically involve faster scoring. Overall, the visualization reinforces the statistical result that higher strike rates are more common in losing outcomes rather than winning ones.
Further Question :- Does a higher strike rate in losses reflect riskier batting, such as chasing high targets or collapsing early?
We test whether the proportion of winning differs between home and away matches using a two‑proportion comparison under Fisher’s significance testing framework.
Main variable: match_outcome (converted to win_binary: win = 1, loss = 0)
Group A: Home matches (innings where the team is playing in one of its designated home cities (venue_city ∈ team_home_city_list)
Group B: Away matches (innings where the team is playing outside its home cities (venue_city ∉ team_home_city_list).
Null Hypothesis (H₀): The proportion of wins in home matches is equal to the proportion of wins in away matches.
\[ \Large P(\text{win} \mid \text{home}) = P(\text{win} \mid \text{away}) ]\]
Alternative Hypothesis (H₁): The proportion of wins in home matches is not equal to the proportion of wins in away matches.
\[ \Large P(\text{win} \mid \text{home}) \neq P(\text{win} \mid \text{away}) ]\]
The comparison involves a binary outcome (match_outcome_binary, where 1 =win and 0 = loss) across two independent groups (home vs away matches). The goal is to determine whether the proportion of wins differs between these two groups, For this the appropriate method is a two‑proportion comparison, implemented using a two‑proportion z‑test. This test produces a p‑value, which aligns directly with Fisher’s significance framework by quantifying how surprising the observed difference in win proportions would be if the null hypothesis were true
#Creating the venue → city mapping
venue_city_map <- c(
"M Chinnaswamy Stadium" = "Bengaluru",
"M.Chinnaswamy Stadium" = "Bengaluru",
"M Chinnaswamy Stadium, Bengaluru" = "Bengaluru",
"Dr DY Patil Sports Academy, Mumbai" = "Mumbai",
"Dr DY Patil Sports Academy" = "Mumbai",
"Eden Gardens, Kolkata" = "Kolkata",
"Eden Gardens" = "Kolkata",
"Wankhede Stadium, Mumbai" = "Mumbai",
"Wankhede Stadium" = "Mumbai",
"Rajiv Gandhi International Stadium, Uppal" = "Hyderabad",
"Rajiv Gandhi International Stadium, Uppal, Hyderabad" = "Hyderabad",
"Rajiv Gandhi International Stadium" = "Hyderabad",
"Feroz Shah Kotla" = "Delhi",
"Arun Jaitley Stadium" = "Delhi",
"Arun Jaitley Stadium, Delhi" = "Delhi",
"Dubai International Cricket Stadium" = "Other",
"Sheikh Zayed Stadium" = "Other",
"Sharjah Cricket Stadium" = "Other",
"Zayed Cricket Stadium, Abu Dhabi" = "Other",
"SuperSport Park" = "Other",
"Kingsmead" = "Other",
"St George's Park" = "Other",
"Newlands" = "Other",
"Buffalo Park" = "Other",
"OUTsurance Oval" = "Other",
"New Wanderers Stadium" = "Other",
"De Beers Diamond Oval" = "Other",
"MA Chidambaram Stadium, Chepauk" = "Chennai",
"MA Chidambaram Stadium, Chepauk, Chennai" = "Chennai",
"MA Chidambaram Stadium" = "Chennai",
"Brabourne Stadium" = "Mumbai",
"Brabourne Stadium, Mumbai" = "Mumbai",
"Narendra Modi Stadium, Ahmedabad" = "Ahmedabad",
"Sardar Patel Stadium, Motera" = "Ahmedabad",
"Himachal Pradesh Cricket Association Stadium" = "Dharamshala",
"Himachal Pradesh Cricket Association Stadium, Dharamsala" = "Dharamshala",
"Punjab Cricket Association Stadium, Mohali" = "Mohali",
"Punjab Cricket Association IS Bindra Stadium" = "Mohali",
"Punjab Cricket Association IS Bindra Stadium, Mohali" = "Mohali",
"Punjab Cricket Association IS Bindra Stadium, Mohali, Chandigarh" = "Mohali",
"Dr. Y.S. Rajasekhara Reddy ACA-VDCA Cricket Stadium" = "Vizag",
"Dr. Y.S. Rajasekhara Reddy ACA-VDCA Cricket Stadium, Visakhapatnam" = "Vizag",
"Maharashtra Cricket Association Stadium" = "Pune",
"Maharashtra Cricket Association Stadium, Pune" = "Pune",
"Sawai Mansingh Stadium, Jaipur" = "Jaipur",
"Sawai Mansingh Stadium" = "Jaipur",
"Barabati Stadium" = "Cuttack",
"Green Park" = "Kanpur",
"Holkar Cricket Stadium" = "Indore",
"JSCA International Stadium Complex" = "Ranchi",
"Barsapara Cricket Stadium, Guwahati" = "Guwahati",
"Nehru Stadium" = "Kochi",
"Saurashtra Cricket Association Stadium" = "Rajkot",
"Subrata Roy Sahara Stadium" = "Pune",
"Shaheed Veer Narayan Singh International Stadium" = "Raipur",
"Vidarbha Cricket Association Stadium, Jamtha" = "Nagpur",
"Maharaja Yadavindra Singh International Cricket Stadium, Mullanpur" = "Chandigarh"
)
# Applying the Mapping
IPL <- IPL |>
mutate(
venue_city = venue_city_map[venue]
)
#Standardising team name
IPL <- IPL |>
mutate(
team = recode(team,
"Delhi Daredevils" = "Delhi Capitals",
"Kings XI Punjab" = "Punjab Kings",
"Royal Challengers Bangalore" = "Royal Challengers Bengaluru",
"Rising Pune Supergiants" = "Rising Pune Supergiant"
)
)
#Creating the team → home‑city mapping
team_home_map <- list(
"Royal Challengers Bengaluru" = c("Bengaluru"),
"Mumbai Indians" = c("Mumbai"),
"Kolkata Knight Riders" = c("Kolkata"),
"Sunrisers Hyderabad" = c("Hyderabad"),
"Deccan Chargers" = c("Hyderabad", "Cuttack"),
"Delhi Capitals" = c("Delhi", "Vizag", "Raipur"),
"Chennai Super Kings" = c("Chennai", "Ranchi"),
"Gujarat Titans" = c("Ahmedabad"),
"Gujarat Lions" = c("Ahmedabad", "Kanpur", "Rajkot"),
"Punjab Kings" = c("Mohali", "Dharamshala", "Indore", "Cuttack", "Nagpur", "Chandigarh"),
"Rajasthan Royals" = c("Jaipur", "Guwahati"),
"Pune Warriors" = c("Pune"),
"Rising Pune Supergiant" = c("Pune"),
"Kochi Tuskers Kerala" = c("Kochi"),
"Lucknow Super Giants" = c("Lucknow")
)
#Adding home/away classification
IPL <- IPL |>
mutate(
team_home_city = team_home_map[team],
is_home = ifelse(venue_city %in% team_home_city, "home", "away")
)
#Filter out neutral venues
IPL <- IPL |>
filter(venue_city != "Other")
#Converting match_outcome to binary
IPL <- IPL |>
mutate(
match_outcome_binary = ifelse(match_outcome == "win", 1, 0)
)
IPL |>
group_by(is_home) |>
summarise(win_rate = mean(match_outcome_binary))
## # A tibble: 2 × 2
## is_home win_rate
## <chr> <dbl>
## 1 away 0.488
## 2 home 0.488
The descriptive statistics show that teams win approximately 48.85% of away matches and 48.80% of home matches, indicating virtually no observable difference in win proportions between the two groups. This suggests that any home‑field advantage in this dataset is extremely small, but Fisher’s framework requires a formal p‑value to determine whether the observed difference could reasonably be attributed to chance.
#Preparing counts for Fisher’s two‑proportion z‑test
home_wins <- sum(IPL$match_outcome_binary[IPL$is_home == "home"])
home_total <- sum(IPL$is_home == "home")
away_wins <- sum(IPL$match_outcome_binary[IPL$is_home == "away"])
away_total <- sum(IPL$is_home == "away")
home_wins
## [1] 5737
home_total
## [1] 11756
away_wins
## [1] 4003
away_total
## [1] 8195
#Two-proportion Z-test
prop.test(
x = c(home_wins, away_wins),
n = c(home_total, away_total),
alternative = "two.sided",
correct = FALSE
)
##
## 2-sample test for equality of proportions without continuity correction
##
## data: c(home_wins, away_wins) out of c(home_total, away_total)
## X-squared = 0.0041332, df = 1, p-value = 0.9487
## alternative hypothesis: two.sided
## 95 percent confidence interval:
## -0.01456108 0.01363617
## sample estimates:
## prop 1 prop 2
## 0.4880061 0.4884686
The two‑proportion test yields a p‑value of \(0.9487\), indicating that the observed difference in win proportions between home and away matches is entirely consistent with what we would expect under the null hypothesis. Under Fisher’s significance testing framework, this means the data do not provide evidence against the null hypothesis, and we therefore fail to reject it. The 95% confidence interval for the difference in proportions is narrow and centered near zero, suggesting that any true home‑field advantage in this dataset is negligible.
Insight
The home and away win proportions (48.80% vs 48.85%) are nearly identical, differing by less than half of one‑tenth of a percentage point.
The extremely high p‑value shows that the observed data align almost perfectly with the assumption that home and away win rates are equal.
Significance
The analysis provides no statistical evidence of a home‑field advantage in this IPL dataset.
The narrow confidence interval indicates that even if a true difference exists, it is too small to be practically meaningful.
IPL |>
group_by(is_home) |>
summarise(win_rate = mean(match_outcome_binary)) |>
ggplot(aes(x = is_home, y = win_rate, fill = is_home)) +
geom_col(width = 0.6) +
scale_y_continuous(labels = scales::percent_format(accuracy = 0.1)) +
labs(
title = "Win Proportions: Home vs Away Matches",
x = "Match Location",
y = "Win Proportion"
) +
theme_minimal(base_size = 14) +
theme(legend.position = "none")
The bar chart comparing home and away win proportions shows two bars of nearly identical height, with both proportions hovering around 48.8%. This visual pattern reinforces the statistical results: there is no meaningful difference in win rates based on match location. The away bar is only marginally higher than the home bar, but the difference is so small that it falls well within the range of random variation expected under the null hypothesis. Overall, the visualization provides a clear, intuitive confirmation that home‑field advantage does not appear to influence match outcomes in this dataset.
Further question :Does home city venue and condition advantage vary by team?