Freedom Sale
Independence Day Special — Unlock the AI Path 70% off our most popular AI course · Limited time offer
--Days
--Hrs
--Min
--Sec
Claim Your Discount
✦ Beginner ⏱ 30 min

🧹 Build a Data Cleaning Toolkit with Pandas

🎯 What You'll Build

A reusable Python toolkit that audits any CSV for missing values, duplicates, wrong types, and outliers — then fixes them and produces a clean output file with a full report.

📋 What You'll Need

1

Audit a dataset for problems

The first step is always to understand what is wrong before fixing anything.

import pandas as pd
import numpy as np

df = pd.read_csv('dirty_data.csv')

def audit(df):
    print(f"Shape: {df.shape[0]:,} rows × {df.shape[1]} columns\n")

    print("Missing values:")
    missing = df.isnull().sum()
    missing_pct = (missing / len(df) * 100).round(1)
    for col in df.columns:
        if missing[col] > 0:
            print(f"  {col}: {missing[col]} missing ({missing_pct[col]}%)")

    print(f"\nDuplicates: {df.duplicated().sum():,} rows")

    print("\nData types:")
    for col, dtype in df.dtypes.items():
        print(f"  {col}: {dtype}")

audit(df)
Shape: 1,000 rows × 6 columns

Missing values:
  age: 47 missing (4.7%)
  salary: 23 missing (2.3%)
  email: 12 missing (1.2%)

Duplicates: 18 rows

Data types:
  name: object
  age: float64
  salary: object    ← should be numeric!
  email: object
2

Fix missing values

Different strategies for different column types — fill numeric with median, drop rows with missing key fields.

def fix_missing(df):
    report = []

    for col in df.select_dtypes(include='number').columns:
        n = df[col].isnull().sum()
        if n > 0:
            median = df[col].median()
            df[col] = df[col].fillna(median)
            report.append(f"  Filled {n} missing '{col}' values with median ({median:.1f})")

    # Drop rows where key text fields are missing
    key_cols = [c for c in ['email', 'name', 'id'] if c in df.columns]
    before = len(df)
    df = df.dropna(subset=key_cols)
    dropped = before - len(df)
    if dropped:
        report.append(f"  Dropped {dropped} rows with missing key fields: {key_cols}")

    return df, report

df, log = fix_missing(df)
for line in log:
    print(line)
Filled 47 missing 'age' values with median (32.0)
  Filled 23 missing 'salary' values with median (52000.0)
  Dropped 12 rows with missing email
3

Remove duplicates and fix data types

Drop exact duplicate rows and convert columns to their correct types.

def fix_types_and_duplicates(df):
    report = []

    # Remove duplicates
    before = len(df)
    df = df.drop_duplicates()
    report.append(f"  Removed {before - len(df)} duplicate rows")

    # Fix salary: remove currency symbols, commas, convert to float
    if 'salary' in df.columns and df['salary'].dtype == object:
        df['salary'] = (df['salary']
            .str.replace(r'[₹$,]', '', regex=True)
            .str.strip()
            .astype(float))
        report.append("  Converted 'salary' from string to float")

    # Standardise text columns: strip whitespace, title-case names
    if 'name' in df.columns:
        df['name'] = df['name'].str.strip().str.title()
        report.append("  Cleaned 'name' column: stripped whitespace, title-cased")

    # Fix email: lowercase
    if 'email' in df.columns:
        df['email'] = df['email'].str.lower().str.strip()
        report.append("  Normalised 'email' to lowercase")

    return df, report

df, log = fix_types_and_duplicates(df)
for line in log:
    print(line)
4

Detect and cap outliers, then save the clean file

Use the IQR method to find outliers and cap them rather than deleting rows.

def fix_outliers(df, columns):
    report = []
    for col in columns:
        if col not in df.columns:
            continue
        Q1  = df[col].quantile(0.25)
        Q3  = df[col].quantile(0.75)
        IQR = Q3 - Q1
        lower = Q1 - 1.5 * IQR
        upper = Q3 + 1.5 * IQR
        outliers = ((df[col] < lower) | (df[col] > upper)).sum()
        df[col] = df[col].clip(lower=lower, upper=upper)
        if outliers:
            report.append(f"  Capped {outliers} outliers in '{col}' to [{lower:.0f}, {upper:.0f}]")
    return df, report

df, log = fix_outliers(df, ['age', 'salary'])
for line in log:
    print(line)

# Save clean file
df.to_csv('clean_data.csv', index=False)
print(f"\nSaved clean_data.csv — {len(df):,} rows remaining")
Capped 11 outliers in 'age' to [15, 68]
  Capped 8 outliers in 'salary' to [18000, 120000]

Saved clean_data.csv — 970 rows remaining
💡 Tip: Run audit() on clean_data.csv after cleaning to verify zero missing values and no duplicates remain — always verify your cleaning worked before passing data to a model.

🎉 You Did It!

Data scientists spend 60-80% of their time cleaning data. This toolkit handles the 5 most common problems: missing values, duplicates, wrong types, inconsistent formatting, and outliers. Drop it into any project as a reusable module.

Found something wrong?

Spotted a bug, broken code, or something that doesn't look right? Tell us what's off and we'll fix it.