Pathubs Logo Mark
PATHUBSFREE CAREER ROADMAPS
HomeExploreDiscoverCompare ⚖️My Progress 📊Support
Student Support & Feedback

Have Questions or Need Help?

Have questions, feedback, or suggestions for new roadmaps and interactive tools? Reach out to our team — we review every message to make practical learning better for everyone.

supportpathubs@gmail.com
Pathubs

Pathubs is an interactive learning platform that combines structured career roadmaps, topic-by-topic learning, and hands-on practice — 100% free with no paywalls.

Popular Careers

  • Frontend Development
  • Backend Development
  • AI & LLM Engineering
  • Full Stack Web Dev
  • Data Analytics

Platform Tools

  • Career Discovery Quiz
  • Compare Careers

Contact & Info

  • About Us
  • supportpathubs@gmail.com
  • Support Pathubs

© 2026 Pathubs. All Rights Reserved. Structured learning, practical content, and hands-on practice for learners worldwide.

AboutPrivacy PolicyTerms & ConditionsSitemapRobots
Home/AI Engineering/Phase 04: Machine Learning/ML Essentials & Preprocessing/Data Preprocessing
AI Engineering Phase 04ML Essentials & Preprocessingscikit-learn 1.9+ CompliantInteractive Laboratory

Data Preprocessing: Imputation, Encoding, Scaling & Leakage Prevention

Raw data is messy, incomplete, unscaled, and full of text strings. Learn the end-to-end discipline of transforming raw tabular observations into leakage-free mathematical matrices using scikit-learn ColumnTransformer, SimpleImputer, OneHotEncoder, and production-grade Pipelines.

Estimated Time:70–90 Minutes
Prerequisites:Pandas, NumPy, ML Fundamentals
Target Architecture:Pipeline + ColumnTransformer
Delivery Mode:Interactive Text & Lab Sandbox
Curriculum Map & Quick Navigation
01 Mental Model of Preprocessing02 Train/Test Split Before Fitting03 Missing Values & Imputation04 Categorical Encoding05 Numerical Feature Scaling06 Outliers & Transformations07 Mixed Data & ColumnTransformer08 Pipelines & Leakage Shield09 Interactive Playground10 Mini Project: Churn Pipeline11 Debugging 4 Production Bugs12 Competency Checklist13 Comprehensive 8-Question Quiz14 AI Engineering Connection
01

The Preprocessing Mental Model

Why raw tabular data cannot be directly ingested by machine learning algorithms

In textbook computer science, data structures are clean and deterministic. In real-world AI engineering, raw datasets arriving from production databases, web analytics, and CSV dumps are messy, incomplete, inconsistently scaled, and filled with arbitrary text strings.

The Raw Data to Model-Ready Feature Matrix Pipeline
Raw Records
(Nulls, Strings, Skewed)
→
Inspection & Cleaning
(Detect types & nulls)
→
Train/Test Separation
(Prevent data leakage)
→
Transformation Engine
(Impute, Encode, Scale)
→
Feature Matrix X
(Dense numeric 2D array)
Machine learning models are mathematical optimizers: they compute dot products, distance metrics, and weight gradients. They cannot multiply a matrix by a missing value (NaN) or a string ('Mumbai').

Common Real-World Data Defects & Preprocessing Remedies

Data DefectExample in Raw TableWhy ML Optimizer BreaksScikit-Learn Remedy
Missing Values (NaN)Age is blank or nullFloating-point calculations produce NaN; gradients become undefinedSimpleImputer
Categorical StringsCity: "Delhi", "Mumbai"Matrices require numbers; string tokens cannot be mathematically differentiatedOneHotEncoder
Disparate Feature ScalesAge (20–60) vs. Income (20k–2M)Income dominates Euclidean distances and gradient updates by orders of magnitudeStandardScaler / RobustScaler
Extreme Outliers1 user earning ₹2.2M among ₹50k peersDistorts sample mean and variance; squashes normal observationsRobustScaler / Log1p
💡 The Golden Rule of Preprocessing
Never normalize or transform data mindlessly. Preprocessing decisions depend strictly on the model family. Tree-based models (Decision Trees, Random Forests, XGBoost) are invariant to monotonic feature scaling, whereas distance-based (k-NN, SVM) and gradient-based models (Logistic Regression, Neural Networks) will completely fail if features are unscaled.
02

Train/Test Split Before Fitting Transformations

Understanding fit() vs transform() and preventing catastrophic data leakage

Every transformer in scikit-learn has internal parameters that are learned from data. For instance, StandardScaler learns the sample mean (μ) and standard deviation (σ); SimpleImputer learns median or mean statistics; and OneHotEncoder learns the list of observed categories.

The Catastrophic Data Leakage vs. Leakage-Free Workflow
❌ BAD: Preprocessing Leakage

Fitting a scaler or imputer on the ENTIRE dataset before splitting:

# DANGEROUS LEAKAGE!
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X) # Test stats leak in!
X_train, X_test, y_train, y_test = train_test_split(X_scaled, y)
The test set's mean and variance are baked into X_train. Your model evaluates unrealistically high on test data and collapses in production.
✓ GOOD: Clean Separation

Split first, fit ONLY on training data, then transform both:

# SAFE & LEAKAGE-FREE
X_train, X_test, y_train, y_test = train_test_split(X, y)
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train) # Learn on train
X_test_scaled = scaler.transform(X_test)      # Apply to test
Test data remains completely unseen. Preprocessing parameters reflect only what was known during training time.

The Triad: fit(), transform(), and fit_transform()

MethodWhat It Actually DoesWhen to Call ItIllegal Usage
transformer.fit(X)Learns internal parameters (means, medians, variance, categories) and saves them in attributes with a trailing underscore (e.g., scaler.mean_).Training data only (X_train)NEVER on X_test or X_val
transformer.transform(X)Uses existing learned parameters to scale, encode, or impute new data into numerical matrices without updating internal state.X_train, X_test, or live inference dataCalling before fit() raises NotFittedError
transformer.fit_transform(X)Convenience method that fits parameters on X and immediately returns the transformed matrix in an optimized single pass.X_train onlyNEVER on X_test (causes data leakage)
03

Missing Values & Imputation Strategies

Why dropping rows is destructive and how to select principled imputation strategies

Beginners often resort to df.dropna() to eliminate missing values. In production AI engineering, blindly dropping rows is dangerous: it destroys statistical power, biases the sample, and crashes production serving if live requests contain missing fields.

⚠️ The Dropna Trap in Production
Suppose your training dataset has 20 columns and 15% of records have at least one null. Calling dropna()discards 15% of your expensive labeled data. Worse: when your model is deployed as a live REST API, if a user sends a payload missing an optional field like "referral_code", your model cannot drop the user—it must output an inference! Imputation guarantees your pipeline handles nulls gracefully.

Scikit-Learn SimpleImputer Strategies

StrategyCalculationBest Used ForKey Tradeoff / Limitation
strategy="median"50th percentile of observed training valuesContinuous skewed numerical data (income, price, download times)Ignores correlations between features
strategy="mean"Arithmetic average of training valuesSymmetric, normally distributed numerical data (exam scores, height)Severely distorted by extreme outliers
strategy="most_frequent"Statistical mode (most common observed value)Categorical columns (city, subscription tier, operating system)Can amplify majority class imbalance
strategy="constant"Replaces nulls with explicit fill_value (e.g. "missing" or -1)When missingness itself conveys a deliberate signal (e.g., promo code not entered)Requires choosing an artificial value

🧪 Interactive Lab 1: Missing Value Imputation Simulator

Select imputation strategies for Age, Income, and City. Execute SimpleImputer and observe how outliers affect the result.

Live Dataset Inspection (Red = Missing in Raw, Green = Imputed)
IDNameAgeAnnual IncomeCityPlanSupport Tickets
101Alice R.29₹72,000MumbaiPro1
102Bob M.NaN (Missing)₹115,000DelhiEnterprise0
103Clara K.44NaN (Missing)MumbaiStarter4
104David S.36₹64,000NaN (Missing)Pro2
105Elena V.52₹240,000PuneEnterprise5
106Farhan T.23₹48,000DelhiStarter0
107Grace L.NaN (Missing)₹89,000PunePro3
108Hari P.61₹2,200,000MumbaiEnterprise1
04

Categorical Data & OneHotEncoder

Transforming text strings into mathematical representations without false ordinal assumptions

Categorical features contain discrete qualitative values. They fall into two distinct mathematical groups:

  • Nominal: Categories with no inherent ordering (e.g. City: "Mumbai", "Delhi", "Pune"; or Operating System: "Linux", "macOS", "Windows").
  • Ordinal: Categories with a natural, monotonic rank (e.g. Education: "High School" < "Bachelor's" < "Master's" < "PhD").
⚠️ The Arbitrary Integer Trap
If you assign arbitrary numbers to nominal categories (Mumbai = 1, Delhi = 2, Pune = 3), a linear regression or neural network assumes:
Pune (3) = Delhi (2) + Mumbai (1)   AND   Average(Delhi, Mumbai) = 1.5
This imposes a completely hallucinated geometric geometry on the data. For nominal data, you must use One-Hot Encoding!

Scikit-Learn OneHotEncoder: Modern API (1.4+)

In current versions of scikit-learn, two critical parameters govern how OneHotEncoder operates:

Python (scikit-learn 1.4+)
from sklearn.preprocessing import OneHotEncoder

encoder = OneHotEncoder(
    sparse_output=False,       # Current API: returns dense 2D NumPy array (sparse=False is removed)
    handle_unknown='ignore'    # Production resilience: encode unseen categories as all zeros
)

# Learn categories from training data: ['Delhi', 'Mumbai', 'Pune']
X_train_cat = encoder.fit_transform(X_train[['city']])

# When test data contains 'Bangalore' (unseen), handle_unknown='ignore' creates [0, 0, 0] safely!
X_test_cat = encoder.transform(X_test[['city']])

⚡ Interactive Lab 2: Categorical Encoding & Unseen Category Tester

Simulate what happens when production data receives a city not seen during training.

05

Numerical Feature Scaling

StandardScaler, MinMaxScaler, and RobustScaler: when and why scale differences matter

Consider a dataset predicting loan approval with two features: Age (range 18 to 70) and Annual Income (range ₹25,000 to ₹1,500,000). If you compute Euclidean distance between two applicants, a difference of ₹10,000 in income completely dwarfs a 30-year difference in age by a factor of hundreds.

The Three Core Scalers Compared

ScalerMathematical FormulaOutput CharacteristicsOutlier Sensitivity
StandardScalerz = (x - μ) / σCenters mean at 0 with standard deviation 1. Values typically span roughly [-3, +3].High: Outliers pull μ and inflate σ
MinMaxScalerx_s = (x - min) / (max - min)Strictly bounded in [0, 1]. Preserves zero values in sparse matrices.Severe: One huge outlier compresses all normal data to 0.01
RobustScalerx_r = (x - Q2) / (Q3 - Q1)Uses median (Q2) and Interquartile Range (IQR). Outliers do not influence scaling.Immune: Robust statistics ignore extreme tails

📊 Interactive Lab 3: Scaler Comparison & Outlier Reaction Sandbox

Change the Executive's income from ₹1.2M to an extreme ₹10M and observe how StandardScaler vs MinMaxScaler vs RobustScaler react.

Scaled Results using StandardScaler
IndividualRaw Annual IncomeScaled RepresentationRelative Distribution Bar
Intern (Priya)₹25,000-0.618
-0.618
Associate (Rohan)₹55,000-0.551
-0.551
Mid-Level (Sana)₹95,000-0.462
-0.462
Senior (Vikram)₹140,000-0.362
-0.362
Executive (Aditya)₹1,200,0001.993
1.993
Notice how with StandardScaler, the extreme income pushes the sample mean far to the right, forcing normal incomes into negative values (-0.45).
06

Outliers & Non-Linear Transformations

Detecting vs. deciding what to do with skewed variables

An outlier is not automatically bad data. In fraud detection, high-net-worth customer analytics, or website latency monitoring, the outliers are often the most critical signals in the entire problem.

1. Investigate First

Is the outlier a sensor glitch (e.g. Age = 999 or -1) or a genuine high-value record? Never delete without verifying domain logic.

2. Winsorization / Capping

Cap values at the 1st and 99th percentiles so extreme observations are pulled to the boundary without discarding the row.

3. Log / Power Transform

Apply np.log1p(x) or PowerTransformer(method='yeo-johnson') to stabilize variance and compress long right tails into Gaussian-like bell curves.

Python (scikit-learn PowerTransformer)
import numpy as np
from sklearn.preprocessing import PowerTransformer

# Method 'yeo-johnson' works with both positive and negative continuous values
pt = PowerTransformer(method='yeo-johnson', standardize=True)

# Compresses skewed distribution into normal bell curve
X_train_transformed = pt.fit_transform(X_train[['income']])
X_test_transformed = pt.transform(X_test[['income']])
07

Mixed-Type Data & ColumnTransformer

Orchestrating simultaneous numeric and categorical transformations cleanly

Real enterprise data is virtually never all-numeric or all-categorical. A typical customer record contains numeric columns (age, monthly_usage) and categorical columns (city, plan_type).

In legacy workflows, data scientists manually sliced DataFrames, scaled numeric columns, one-hot encoded strings, and manually glued them back together with np.hstack(). This pattern was brittle, error-prone, and guaranteed data leakage in cross-validation.

The Architecture of ColumnTransformer
ColumnTransformer(transformers=[...])
Branch A: Numeric Pipeline
Columns: ['age', 'income', 'tickets']
1. SimpleImputer(strategy='median')
2. StandardScaler()
Branch B: Categorical Pipeline
Columns: ['city', 'plan']
1. SimpleImputer(strategy='most_frequent')
2. OneHotEncoder(sparse_output=False, handle_unknown='ignore')
↓ Merged Horizontally into One Continuous Feature Matrix X (shape: [N, Features])
Python (scikit-learn ColumnTransformer with set_output)
from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import StandardScaler, OneHotEncoder

num_cols = ['age', 'income', 'tickets']
cat_cols = ['city', 'plan']

preprocessor = ColumnTransformer(
    transformers=[
        ('num', Pipeline([
            ('imputer', SimpleImputer(strategy='median')),
            ('scaler', StandardScaler())
        ]), num_cols),
        ('cat', Pipeline([
            ('imputer', SimpleImputer(strategy='most_frequent')),
            ('onehot', OneHotEncoder(sparse_output=False, handle_unknown='ignore'))
        ]), cat_cols)
    ]
)

# Retain pandas DataFrame with readable feature names!
preprocessor.set_output(transform='pandas')

X_train_clean = preprocessor.fit_transform(X_train)
X_test_clean = preprocessor.transform(X_test)
08

Pipelines & Complete Leakage Prevention

Coupling transformations with estimators into an indivisible production unit

The ultimate weapon against data leakage and training-serving skew is the scikit-learn Pipeline. Instead of maintaining independent preprocessor and classifier objects, you bind them into a single estimator:

Python (End-to-End Pipeline)
from sklearn.pipeline import Pipeline
from sklearn.linear_model import LogisticRegression

# Bundle Preprocessing AND Model together!
model_pipeline = Pipeline([
    ('preprocess', preprocessor),
    ('classifier', LogisticRegression(random_state=42))
])

# Single call fits preprocessor on X_train AND trains logistic regression!
model_pipeline.fit(X_train, y_train)

# Inference automatically passes raw records through preprocessor before predicting!
predictions = model_pipeline.predict(X_test)
🛡️ Why Cross-Validation Demands a Pipeline
When you run cross_val_score(model_pipeline, X, y, cv=5), scikit-learn automatically re-fits the imputer, scaler, and one-hot encoder on the 4 training folds for each split, and transforms the 5th holdout fold using only those fold-specific statistics. If you scaled data outside the pipeline, all 5 folds would suffer from information leakage!
09

Practical Preprocessing Playground

Configure, assemble, and execute a full ColumnTransformer on raw customer records

⚙️ Interactive Feature Engineering & Preprocessing Workbench

Select features, set transformation rules, and run the pipeline to inspect the synthesized feature matrix.

1. Numerical Features
2. Categorical Features
OneHotEncoder(sparse_output=False, handle_unknown='ignore')
3. Output Representation
10

Mini Project: Customer Churn Preprocessing Pipeline

End-to-end hands-on assembly of an enterprise-ready pipeline

In this project, you are given raw customer records containing missing values, categorical plan types, and disparate usage metrics. Step through the 4 production stages to build a leakage-free predictive pipeline.

🚀 Customer Churn Preprocessing Workbench

Progress through: 1. Split → 2. ColumnTransformer → 3. Full Pipeline → 4. Inference

1
Stage 1: Train/Test Split (80/20)
Separate X and y; guarantee test set isolation before touching any transformer.
2
Stage 2: ColumnTransformer Architecture
Define Numeric Pipeline (median imputer + RobustScaler) and Categorical Pipeline (mode imputer + OneHotEncoder).
3
Stage 3: make_pipeline(preprocessor, LogisticRegression())
Encapsulate transformations directly with the classifier. Call fit() on X_train.
4
Stage 4: Test Evaluation & Production Inference
Predict on X_test with novel categories handled seamlessly via handle_unknown='ignore'.
11

Debugging 4 Classic Preprocessing Bugs

Analyze broken production code, toggle the architectural fix, and learn why

Bug 1: Scaling Before Splitting (Data Leakage)
❌ BUGGY: Premature fit_transform
# BUGGY CODE:
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X) # CATASTROPHIC: Test statistics leak into train!
X_train, X_test, y_train, y_test = train_test_split(X_scaled, y, test_size=0.2)
Why this happens: When you fit a scaler across the entire dataset before splitting, the test set's mean and standard deviation influence X_train. Your validation metrics become overly optimistic, giving you false confidence before deploying.
Bug 2: Unseen Categories Crash Production Inference
❌ BUGGY: Default handle_unknown='error'
# CRASHES ON LIVE INFERENCE:
encoder = OneHotEncoder(sparse_output=False) # Defaults to handle_unknown='error'
encoder.fit(X_train[['city']]) # Observed: Mumbai, Delhi, Pune
# When test data or API request has city='Kolkata', raises ValueError!
Why this happens: In production web systems, users frequently enter new values (new browser versions, rare cities). By default, OneHotEncoder crashes when encountering a novel string. Setting handle_unknown='ignore' produces all zeros for those columns safely.
Bug 3: Ordinal Numbers for Nominal Variables
❌ BUGGY: OrdinalEncoder on Nominal Cities
# HARMFUL FOR LINEAR/DISTANCE MODELS:
from sklearn.preprocessing import OrdinalEncoder
encoder = OrdinalEncoder()
X['city_code'] = encoder.fit_transform(X[['city']])
# Imposes: Pune(2) > Delhi(1) > Mumbai(0). Linear models assume 2*Delhi = Pune!
Why this happens: Nominal categories have no mathematical magnitude. Forcing them into 1, 2, 3 tricks optimization algorithms into calculating nonsensical gradients. Reserve OrdinalEncoderstrictly for variables with real ranks (e.g. "Low", "Medium", "High").
Bug 4: The Reckless dropna() Data Loss Trap
❌ BUGGY: df.dropna()
# DESTRUCTIVE TO TRAINING & TEST DATA:
df_clean = df.dropna() # Discards 40% of rows!
# In live inference, cannot drop incoming user request if optional field is blank!
Why this happens: Calling dropna() discards valuable samples and leaves your serving architecture with zero strategy to handle nulls in real-time user requests. Always use SimpleImputer within your pipeline.
12

What You Should Know Now: Competency Checklist

Verify your mastery of production data preprocessing principles

Check off each core competency as you master it. Aim for 100% completion before building production ML models:

Completed 0 of 10 competencies
13

Comprehensive Knowledge Assessment Quiz

Test your practical intuition across 8 production-grade preprocessing scenarios

Question 1 of 8Score: 0 / 8

Why must you split your dataset into training and test sets BEFORE calling fit() or fit_transform() on any transformer?

14

Why Preprocessing Matters for AI Engineering

From tabular feature pipelines to LLM tokenization, embeddings, and real-time serving

Many software engineers assume data preprocessing is an obsolete concern of 2015-era classical machine learning. In reality, the fundamental challenge of data representation and training-serving parity is even more vital in modern AI systems:

1. Training-Serving Skew

If an online prediction microservice scales input data with a different formula than the offline training script, model accuracy degrades silently. Bundling preprocessors in Pipelines completely guarantees code parity between training and serving.

2. Vector Embeddings & LLM Guardrails

Dense vector embeddings from models like OpenAI or Cohere require L2-normalization (Normalizer) before cosine similarity indexing. Preprocessing logic governs retrieval precision in RAG systems.

3. Feature Stores & Online Serving

Enterprise feature stores (e.g. Feast, Hopsworks, SageMaker) store point-in-time correct transformations to prevent data leakage across customer timelines. Understanding transformers prepares you for distributed feature engineering.

← Previous TopicML FundamentalsNext Topic →Feature Engineering