100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Data Analysis & Feature Engineering
55 minintermediate

Practice — Full EDA on a Housing Dataset

What You'll Build

In this exercise you will build a complete, reusable exploratory data analysis pipeline and apply it end to end to a housing-style dataset framed in cricket terms — analysing factors that predict a player's market valuation. You will implement the full EDA workflow from this module as executable functions: structure inspection, data-quality assessment, univariate profiling for both continuous and categorical variables, bivariate relationship analysis, outlier detection, and a summary of findings with an actionable feature-engineering plan. This consolidates every concept from the module into one practical tool that mirrors exactly how a data scientist opens any new dataset. By the end you will have an EDA engine you can point at any dataset to produce a thorough, documented exploration that surfaces quality issues, distributions, relationships, and anomalies in a single run.

Analogy🏏Cricket
🏏 Think of it like cricket: Building this pipeline is like a head analyst codifying the entire pre-match preparation routine into a single reusable playbook — pitch inspection, opposition profiling, matchup analysis, and threat assessment — that can be run before any match against any opponent. Just as the playbook turns scattered preparation habits into one repeatable, complete routine, your EDA pipeline turns scattered exploration steps into one repeatable engine. Just as a good playbook ensures no aspect of preparation is forgotten before any match, your pipeline ensures no aspect of exploration is skipped on any dataset. The insight is that codifying the full exploration workflow into a reusable tool is what makes thorough EDA fast, consistent, and complete every time.

Prerequisites

  • Python 3.10 or later with NumPy, SciPy, pandas, and scikit-learn installed.
  • Mastery of the EDA workflow and checklist from Lesson 1.
  • Command of univariate analysis for continuous and categorical variables from Lesson 2.
  • Understanding of bivariate analysis and confounding from Lesson 3.
  • Knowledge of outlier detection methods from Lesson 4.

Setup & Project Structure

You will create a project with an EDA engine module containing the reusable analysis functions and a script that runs the engine on the housing dataset. Separating the reusable engine from the dataset-specific script lets you apply the same exploration to any future data. Install the dependencies into a virtual environment and seed any randomness so the analysis, including outlier detection, is reproducible across runs for reliable comparison and debugging.

Analogy🏏Cricket
🏏 Think of it like cricket: a smart side doesn't build a brand-new practice routine for every opponent — it develops a reusable set of net drills and fitness protocols that can be pointed at any upcoming team, then layers opponent-specific prep on top. That is exactly why you separate a reusable EDA engine module, holding your general analysis functions, from the dataset-specific script that aims them at the housing data: build the engine once and you can explore any future dataset with it, just as a well-designed net session works against any tour. Just as a coach fixes the bowling-machine settings and pitch so today's session can be repeated identically tomorrow, you install dependencies into an isolated virtual environment and seed every source of randomness — including the outlier detection — so the whole analysis is reproducible. Just as a structured training ground keeps drills organised and repeatable, a clean project structure keeps your engine and script cleanly divided. The payoff: a disciplined setup you can reuse and trust match after match.
bash
# Create the project
mkdir cricket_eda_pipeline && cd cricket_eda_pipeline
python -m venv venv
source venv/bin/activate          # Windows: venv\Scripts\activate
pip install numpy scipy pandas scikit-learn

# Project files
touch eda_engine.py run_eda.py

# Verify
python -c "import numpy, scipy, pandas, sklearn; print('EDA stack ready')"

Step 1 — Foundation

Step 1 builds the foundation: structure-inspection and data-quality functions that report shape, types, missing values, and duplicates. This is the foundation because, per the workflow, understanding structure and quality must precede all analysis, and these functions implement the critical opening checks that catch type errors and missingness before they corrupt anything downstream. Getting this stage right ensures every later stage operates on data the analyst genuinely understands.

Analogy🏏Cricket
🏏 Think of it like cricket: Step 1 is like the opening pitch-and-conditions inspection — establishing the basic facts of the playing surface before any tactical planning. Just as the pitch inspection must come first because every tactic depends on the conditions, the structure and quality checks must come first because every analysis depends on understanding them. Just as a misread pitch ruins the game plan, missed type errors or missingness ruin the analysis. The insight is that the foundational structure-and-quality inspection is the bedrock the whole exploration stands on.
python
# eda_engine.py
import numpy as np
import pandas as pd

def inspect_structure(df):
    """Report shape, dtypes, and a sample - the first checklist step."""
    return {
        "shape": df.shape,
        "dtypes": df.dtypes.astype(str).to_dict(),
        "memory_mb": round(df.memory_usage(deep=True).sum() / 1e6, 2),
    }

def assess_quality(df):
    """Quantify missing values and duplicates - the quality gate."""
    missing = df.isnull().sum()
    return {
        "missing_by_col": missing[missing > 0].to_dict(),
        "missing_pct": (df.isnull().mean() * 100).round(1)[lambda x: x > 0].to_dict(),
        "duplicate_rows": int(df.duplicated().sum()),
    }

if __name__ == "__main__":
    df = pd.read_csv("player_valuation.csv")
    print("Structure:", inspect_structure(df))
    print("Quality:", assess_quality(df))

Step 2 — Core Logic

Step 2 builds the univariate profiling core: a function that profiles every variable with type-appropriate summaries — distributional statistics and skew for continuous variables, frequencies and cardinality for categoricals — and flags quality issues. This is the analytical core because univariate understanding of every variable is the prerequisite for relationship analysis and feature engineering, and producing it uniformly across all variables guarantees nothing is skipped. The function dispatches by type, applying the right summary to each column.

Analogy🏏Cricket
🏏 Think of it like cricket: Step 2 is like profiling every single player in both squads with the metrics appropriate to their role — batting stats for batsmen, bowling figures for bowlers — so each is understood individually before matchups are considered. Just as each player gets the right kind of profile, each variable gets a type-appropriate summary. Just as profiling every player ensures none is overlooked before the matchup analysis, profiling every variable ensures none is skipped before relationship analysis. The insight is that complete, type-appropriate univariate profiling is the analytical core that everything downstream builds on.
python
# eda_engine.py (continued)
from scipy import stats

def profile_variable(s):
    """Type-appropriate univariate profile of one column."""
    if s.dtype.kind in "fi":                     # numeric
        clean = s.dropna()
        return {
            "type": "continuous",
            "mean": round(clean.mean(), 2), "median": round(clean.median(), 2),
            "std": round(clean.std(), 2), "skew": round(clean.skew(), 2),
            "range": (round(clean.min(), 2), round(clean.max(), 2)),
        }
    return {                                       # categorical
        "type": "categorical",
        "cardinality": s.nunique(),
        "top": s.value_counts().head(3).to_dict(),
        "rare_pct": round((s.value_counts(normalize=True) < 0.02).mean() * 100, 1),
    }

def profile_all(df):
    return {col: profile_variable(df[col]) for col in df.columns}

Step 3 — Integration & Enhancement

Step 3 integrates bivariate analysis and outlier detection, then assembles everything into a findings summary with an actionable feature-engineering plan. You will add a function that computes the correlation of each numeric feature with the target valuation and flags highly inter-correlated feature pairs, plus IQR-based outlier detection, and a final function that turns all findings into a concrete plan. This integration completes the pipeline by connecting individual-variable understanding to relationships and anomalies, and by converting the entire exploration into the actionable output that makes EDA worthwhile.

Analogy🏏Cricket
🏏 Think of it like cricket: Step 3 is like completing the preparation by analysing matchups between players, flagging anomalous performances, and turning the whole survey into a concrete game plan with specific instructions. Just as the matchup analysis and threat flags feed into an actionable plan, the bivariate and outlier analysis feed into the feature-engineering plan. Just as scattered observations are useless without a plan, EDA findings are useless without being made actionable. The insight is that integrating relationships and anomalies and converting everything into a concrete plan is what completes the pipeline and delivers EDA's real value.
python
# eda_engine.py (continued)
def relationships(df, target):
    """Correlation of numeric features with target, and redundant pairs."""
    num = df.select_dtypes("number")
    target_corr = num.corr()[target].drop(target).round(3).sort_values(key=abs,
                                                                        ascending=False)
    corr_matrix = num.corr().abs()
    redundant = [(a, b) for a in corr_matrix.columns for b in corr_matrix.columns
                 if a < b and corr_matrix.loc[a, b] > 0.85]
    return {"target_correlation": target_corr.to_dict(), "redundant_pairs": redundant}

def detect_outliers(df):
    """IQR-fence outlier counts per numeric column."""
    out = {}
    for col in df.select_dtypes("number").columns:
        s = df[col].dropna()
        q1, q3 = s.quantile([0.25, 0.75]); iqr = q3 - q1
        out[col] = int(((s < q1 - 1.5*iqr) | (s > q3 + 1.5*iqr)).sum())
    return out

def build_plan(df, target):
    """Turn all findings into an actionable feature-engineering plan."""
    plan = {"log_transform": [], "group_rare": [], "drop_redundant": []}
    for col in df.select_dtypes("number").columns:
        s = df[col].dropna()
        if s.skew() > 1.0 and (s > 0).all():
            plan["log_transform"].append(col)
    for col in df.select_dtypes("object").columns:
        if (df[col].value_counts(normalize=True) < 0.02).any():
            plan["group_rare"].append(col)
    plan["drop_redundant"] = relationships(df, target)["redundant_pairs"]
    return plan

Step 4 — Testing & Verification

Now you will run the complete EDA pipeline on the housing valuation dataset and verify the output is coherent and actionable. Confirm the structure and quality checks report sensible shapes and missingness, the univariate profiles correctly classify and summarise each variable, the relationship analysis surfaces the features most correlated with valuation, the outlier detection flags reasonable counts, and the feature-engineering plan lists concrete actions. A complete, sensible report across all stages verifies the pipeline works end to end.

Analogy🏏Cricket
🏏 Think of it like cricket: before the real series you play a full dress-rehearsal warm-up match to confirm all your preparation actually holds up under match conditions — and that is exactly what running the complete EDA pipeline on the housing data does. Just as you glance at the scoreboard to check it reads a sensible total and the right number of players are accounted for, you confirm the structure and quality checks report sensible shapes and plausible missingness. Just as you verify each player is listed in their correct role — batsman, bowler, keeper — you check the univariate profiles correctly classify and summarise every variable. Just as a warm-up reveals which opposition threats correlate most with danger, the relationship analysis should surface the features most strongly tied to valuation, and the outlier detection should flag genuinely reasonable freak cases, not nonsense. And just as you review the footage afterward to be sure nothing looked broken, you verify the whole output is coherent and actionable. The payoff: you trust the pipeline before it matters.
bash
# run_eda.py
import pandas as pd
from eda_engine import (inspect_structure, assess_quality, profile_all,
                        relationships, detect_outliers, build_plan)

df = pd.read_csv("player_valuation.csv")
TARGET = "valuation"

print("=== 1. STRUCTURE ===")
print(inspect_structure(df))
print("\n=== 2. QUALITY ===")
print(assess_quality(df))
print("\n=== 3. UNIVARIATE (sample) ===")
profiles = profile_all(df)
for col in list(profiles)[:3]:
    print(f"  {col}: {profiles[col]}")
print("\n=== 4. RELATIONSHIPS ===")
rel = relationships(df, TARGET)
print(f"  Top correlations with {TARGET}: "
      f"{dict(list(rel['target_correlation'].items())[:3])}")
print(f"  Redundant pairs: {rel['redundant_pairs']}")
print("\n=== 5. OUTLIERS ===")
print(f"  {detect_outliers(df)}")
print("\n=== 6. FEATURE-ENGINEERING PLAN ===")
print(f"  {build_plan(df, TARGET)}")

# Verify: each stage produces sensible, actionable output end to end.

Warning: A common pipeline mistake is computing the target correlation or outlier statistics before checking data quality, so missing values or a mis-typed column silently distort the results. Always run the structure and quality stages first and act on their findings before trusting later stages — an EDA pipeline that analyses relationships on data riddled with undetected missingness or type errors produces confident but corrupted output. The stage order is not cosmetic; it enforces the dependency that each step relies on the verified output of the last.

Extension Challenge: Extend the pipeline to generate visualisations automatically — histograms for each continuous variable, bar charts for categoricals, a correlation heatmap, and grouped box plots of the target against each categorical — saving them to a report folder. As a stretch goal, integrate a multivariate Isolation Forest outlier pass alongside the IQR detection and flag any records that both methods agree are anomalous, since agreement between a univariate and a multivariate method is strong evidence a record warrants investigation.

  • A reusable EDA pipeline codifies the full workflow into functions applicable to any dataset for fast, consistent exploration.
  • Structure and quality inspection must run first, catching type errors and missingness before they corrupt later stages.
  • Univariate profiling dispatches type-appropriate summaries to every variable, guaranteeing none is skipped.
  • Relationship analysis surfaces features correlated with the target and flags redundant, highly inter-correlated pairs.
  • Outlier detection flags anomalies, and combining univariate and multivariate methods strengthens the evidence.
  • The pipeline must convert all findings into an actionable feature-engineering plan, the real payoff of EDA.
  • Stage order enforces dependencies, so each step relies on the verified output of the previous one.
Lesson 6 of 35
0% complete