100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Statistics & Probability for Data Science
45 minintermediate

Compute Descriptive Stats and Distributions

What You'll Build

In this first stage of the capstone you will build the descriptive and distributional analysis of the clinical-trial dataset, producing a thorough summary of every variable and characterising the distributions that govern them. You will compute central tendency, spread, and shape for the continuous variables broken down by treatment group, generate five-number summaries, detect outliers, and fit distributions to the skewed fitness variable to confirm it is gamma rather than normal. This stage exists because no inference is trustworthy until you understand the data's structure, and the descriptive findings here will directly inform which tests are valid in the next stage. By the end you will have a complete descriptive foundation on which the hypothesis testing and estimation will rest.

Analogy🏏Cricket
🏏 Think of it like cricket: Building a Monte Carlo simulator is like a team running thousands of practice scenarios in the nets to estimate how often a tactic works, rather than relying on a coach's theoretical hunch. Just as repeatedly playing out the scenario and counting successes reveals the true odds far more reliably than armchair reasoning, simulating thousands of random matches reveals probabilities the maths might struggle to express. Just as more net sessions give a sharper estimate, more simulated trials give a more accurate probability. The insight is that when a probability is hard to derive, you can let randomness itself compute the answer by playing the scenario out enough times to see the pattern emerge.

Prerequisites

  • Python 3.10 or later with NumPy, SciPy, and pandas installed.
  • The capstone dataset cricket_trial.csv generated in Lesson 31.
  • Mastery of central tendency, spread, and shape from Module 1.
  • Understanding of distribution fitting and goodness-of-fit from Module 3.
  • Comfort with pandas grouping and aggregation operations.

Setup & Project Structure

You will work in the capstone project directory alongside the dataset, creating a descriptive-analysis module that loads the data and produces the summary. Keeping each capstone stage in its own module while sharing the dataset keeps the growing analysis organised and lets each stage be reviewed independently. Ensure the dataset from Lesson 31 is present, and import the same libraries so the analysis is consistent across stages.

Analogy🏏Cricket
🏏 Think of it like cricket: setting up this simulation project is like building a reliable practice net before running match scenarios. You create one simulator module — the 'random delivery engine' that bowls virtual balls — the way a bowling machine can reproduce any spell on demand, and you keep the experiments script separate, like the coach's session plan that decides which drills to run today. Just as one machine serves countless practice plans, separating the engine from the experiments lets you reuse the same simulator for many different probability questions. Crucially, just as a bowling machine set to identical settings must deliver the identical sequence so two players face a fair, repeatable test, you seed the random number generator so results are deterministic across runs — essential for debugging and for anyone reproducing your work. The payoff: a clean, seeded structure means your Monte Carlo experiments are trustworthy and repeatable, not a different answer every time you press start.
bash
# In the capstone project directory (contains cricket_trial.csv)
touch descriptive_analysis.py

# Verify the dataset is present
python -c "import pandas as pd; df = pd.read_csv('cricket_trial.csv'); print(f'{len(df)} rows loaded')"

Step 1 — Foundation

Step 1 builds the foundational group-wise descriptive summary: a function that computes the mean, median, standard deviation, and IQR for a continuous variable, broken down by treatment group. This is the foundation because comparing the treatment and control groups descriptively is the first glimpse of whether the regime had an effect, and these summaries frame every later inference. Computing both mean and median lets you immediately spot skew through their divergence, applying a Module 1 diagnostic to the real data.

Analogy🏏Cricket
🏏 Think of it like cricket: Step 1 is like building a perfectly weighted bowling machine that delivers each type of ball with exactly the right frequency — dots most often, wickets rarely. Just as the machine's weighting must faithfully match the real probabilities for the practice to be meaningful, your sampler's probability vector must faithfully encode the delivery distribution. Just as one bowled ball is the atom of an over, one sampled outcome is the atom of every simulation. The insight is that a faithful single-event sampler is the engine from which all larger probabilistic scenarios are assembled.
python
# descriptive_analysis.py
import numpy as np
import pandas as pd

trial = pd.read_csv("cricket_trial.csv")

def group_summary(df, column, group_col="group"):
    """Central tendency and spread for a column, split by group."""
    summary = {}
    for grp, sub in df.groupby(group_col)[column]:
        q1, q3 = np.percentile(sub, [25, 75])
        summary[grp] = {
            "n": len(sub),
            "mean": sub.mean(),
            "median": sub.median(),
            "std": sub.std(ddof=1),
            "iqr": q3 - q1,
            "mean_median_gap": sub.mean() - sub.median(),  # skew hint
        }
    return summary

# Strike rate improvement = after - before
trial["improvement"] = trial["strike_after"] - trial["strike_before"]
for grp, stats_d in group_summary(trial, "improvement").items():
    print(f"{grp:10}: mean={stats_d['mean']:.2f}, median={stats_d['median']:.2f}, "
          f"std={stats_d['std']:.2f}")

Step 2 — Core Logic

Step 2 adds the shape and outlier analysis: a function producing the five-number summary, skewness, excess kurtosis, and IQR-fence outlier detection for any variable. This is the analytical core of the descriptive stage because it characterises the distribution's shape and flags anomalies, directly determining whether parametric tests will be valid later. Applying this to the skewed fitness variable will reveal its right skew, foreshadowing the need for non-parametric handling in the inference stage.

Analogy🏏Cricket
🏏 Think of it like cricket: Step 2 is like bowling ten thousand practice overs and tallying how many were maidens to estimate your real maiden-over rate. Just as the proportion of maidens across thousands of overs converges to your true maiden probability, the fraction of successful trials in a Monte Carlo run converges to the true event probability. Just as ten overs would give a noisy estimate but ten thousand a reliable one, small simulations are noisy while large ones are precise. The insight is that empirical frequency over many independent trials is a direct, trustworthy estimate of probability.
python
# descriptive_analysis.py (continued)
from scipy import stats

def shape_analysis(values):
    """Five-number summary, shape statistics, and IQR-fence outliers."""
    values = np.asarray(values)
    q1, q3 = np.percentile(values, [25, 75])
    iqr = q3 - q1
    lo, hi = q1 - 1.5 * iqr, q3 + 1.5 * iqr
    skew = stats.skew(values)
    return {
        "five_number": {
            "min": float(values.min()), "q1": float(q1),
            "median": float(np.median(values)), "q3": float(q3),
            "max": float(values.max()),
        },
        "skewness": skew,
        "excess_kurtosis": stats.kurtosis(values),
        "shape": ("right-skewed" if skew > 0.5 else
                  "left-skewed" if skew < -0.5 else "symmetric"),
        "outliers": values[(values < lo) | (values > hi)].tolist(),
    }

fitness_shape = shape_analysis(trial["fitness"])
print(f"Fitness shape: {fitness_shape['shape']}, skew={fitness_shape['skewness']:.2f}")
print(f"Fitness outliers: {len(fitness_shape['outliers'])} flagged")

Step 3 — Integration & Enhancement

Step 3 integrates distribution fitting to formally characterise the fitness variable, confirming with goodness-of-fit testing that it follows a gamma rather than a normal distribution. This completes the descriptive stage by moving from informal shape description to a validated distributional model, applying the Module 3 fitting-and-validation workflow to the real capstone data. The confirmed distribution both documents the data's nature and justifies the non-parametric choices the inference stage will make for this variable.

Analogy🏏Cricket
🏏 Think of it like cricket: Step 3 is like watching a new bowler over many overs and continuously revising your estimate of how good he really is, starting from a cautious prior and sharpening it with each wicket or wicketless over. Just as your belief about his true skill tightens as evidence accumulates, the Bayesian posterior concentrates as more simulated deliveries are observed. Just as one good over barely moves your judgement but fifty overs settle it, each observation nudges the posterior proportionally. The insight is that simulation and Bayesian updating combine naturally: simulation produces evidence, and Bayes turns that evidence into refined belief.
python
# descriptive_analysis.py (continued)
def characterise_distribution(values, candidates=("norm", "gamma", "lognorm")):
    """Fit candidates and pick the best by KS goodness-of-fit p-value."""
    values = np.asarray(values)
    results = {}
    for name in candidates:
        dist = getattr(stats, name)
        params = dist.fit(values)
        ks_stat, ks_p = stats.kstest(values, name, args=params)
        results[name] = {"params": params, "ks_p": ks_p}
    best = max(results, key=lambda k: results[k]["ks_p"])
    return best, results

best_dist, fit_results = characterise_distribution(trial["fitness"])
print(f"Best-fitting distribution for fitness: '{best_dist}'")
for name, r in fit_results.items():
    print(f"  {name:8}: KS p-value = {r['ks_p']:.4f}")
print("Expected: gamma fits well, normal is rejected -> use non-parametric later.")

Step 4 — Testing & Verification

Now you will run the complete descriptive analysis and verify the findings match the dataset's known construction. Confirm the treatment group shows a larger mean improvement than control, that the fitness variable is identified as right-skewed and best fit by the gamma distribution, and that outlier counts are reasonable. These descriptive findings recovering the embedded ground truth verify your analysis is correct and set up the inference stage.

Analogy🏏Cricket
🏏 Think of it like cricket: verifying a Monte Carlo simulation is like trusting a batting average only after enough innings. Estimate the chance of a maiden over from ten simulated overs and the number jumps around wildly, just as a batter's average after two innings tells you little; run ten thousand overs and it settles onto the true value, exactly as an average stabilises over a long career. Just as facing more deliveries lets you read a bowler's real wicket-taking rate rather than being fooled by a lucky first spell, your Bayesian posterior mean creeps toward the true hidden wicket rate as more balls are observed. Convergence toward the known expected answer is your proof the engine and the inference are wired correctly, the way a scorer trusts the system once it reproduces a result everyone already agrees on. The payoff: watching estimates lock onto known truths as trials grow is the trust-check that lets you believe the simulator on questions you can't solve by hand.
bash
# Run the full descriptive analysis
import pandas as pd
from descriptive_analysis import (trial, group_summary, shape_analysis,
                                   characterise_distribution)

print("=== TREATMENT EFFECT (descriptive) ===")
for grp, s in group_summary(trial, "improvement").items():
    print(f"  {grp:10}: mean improvement = {s['mean']:.2f}")

print("\n=== FITNESS DISTRIBUTION ===")
fs = shape_analysis(trial["fitness"])
print(f"  Shape: {fs['shape']}, skewness: {fs['skewness']:.2f}")
best, _ = characterise_distribution(trial["fitness"])
print(f"  Best distribution: {best}")

# Expected: treatment mean improvement (~9) > control (~1);
# fitness right-skewed, best fit gamma -> confirms ground truth.

Warning: Do not compute group means and immediately conclude the treatment works — descriptive differences are observations, not inferences. A larger mean improvement in the treatment group is only a hint; it could still arise from chance, and only the hypothesis testing in the next stage can establish whether the difference is real. Resist the strong temptation to draw conclusions from descriptive statistics alone, which is a classic way analyses overreach beyond what the evidence supports.

Extension Challenge: Extend the descriptive analysis to produce the same group-wise summaries broken down further by player role, revealing whether the regime's apparent effect differs across batsmen, bowlers, and allrounders. As a stretch goal, generate diagnostic plots — grouped boxplots of improvement and a histogram of fitness with the fitted gamma density overlaid — so the descriptive findings are communicated visually as well as numerically.

  • Descriptive analysis must precede inference; understanding the data's structure determines which tests are valid.
  • Group-wise summaries of mean, median, spread, and IQR give the first glimpse of a treatment effect.
  • The mean-median gap is a free diagnostic of skew applied directly to the real data.
  • Shape statistics and IQR-fence outlier detection characterise distributions and flag anomalies for later test choices.
  • Distribution fitting with goodness-of-fit validation confirms the fitness variable is gamma, justifying non-parametric handling.
  • Descriptive differences are observations, not conclusions; only hypothesis testing can establish whether an effect is real.
Lesson 32 of 35
0% complete