Part 2: Data & Feature Engineering Lesson 08 / 56
Estimated Reading: 12–15 mins Level: Beginner

Data Cleaning: Purification & Preparation

Scientific Strategies for Missing Values, Duplicate Records, String Sanitization, Outliers, and Data Leakage Prevention

Core Learning Objectives

Principles of data cleaning and quality dimensions; Missing value taxonomy (MCAR, MAR, MNAR) and robust imputation; Duplicate record detection with Composite Keys; String sanitization and type casting; Tukey's IQR outlier fencing and Winsorization capping; and preventing catastrophic Data Leakage in ML pipelines.

1. Introduction: Transforming Raw Noise into Machine Learning Fuel

How accurately a machine learning model generalizes in production depends heavily—often up to 80%—on the hygiene and integrity of its training data. In real-world enterprise environments, raw data arrives messy and corrupted. Network timeouts, human typing blunders, database migration glitches, and inconsistent API schemas inevitably contaminate incoming datasets.

Consider an e-commerce sales dataset analyzed by Byteion. Upon initial inspection, several severe issues emerge:

  • Several premium laptop entries have missing (None / NaN) prices.
  • Network retries caused identical customer transactions to be recorded twice.
  • Ordered quantity is represented inconsistently as numbers ("2") and words ("two").
  • A single product category is recorded inconsistently as "Fashion", "fashion", and whitespace-padded " Fashion ".

Passing such corrupted records directly to a machine learning estimator triggers either outright runtime exceptions (ValueError: Input contains NaN) or causes the model to learn distorted, biased relationships. The systematic engineering methodology developed to remediate these defects is Data Cleaning.

Formal Definition of Data Cleaning

Data Cleaning (or Data Cleansing) is the systematic engineering process of detecting and correcting (or removing) corrupt, inaccurate, incomplete, duplicated, or improperly formatted records from a dataset, ensuring structural validity and consistency prior to downstream feature engineering and model training.

Crucially, data cleaning does not mean deleting all unusual observations. Outliers frequently represent legitimate, high-value phenomena (such as large enterprise bulk purchases or credit card fraud). Every modification or record removal must be anchored in clear domain reasoning.

2. The 6 Core Dimensions of Data Quality

In enterprise data engineering, datasets are evaluated against 6 standardized dimensions of quality:

Quality Dimension Definition & Significance Real-World Case Example
1. Accuracy Degree to which recorded data reflects true ground reality. Customer age recorded as 250 years or unit price recorded as -$50.
2. Consistency Uniformity of representation, formatting, and syntax across tables. Standardizing "Dhaka", "dhaka", and "DHK" into a single canonical token.
3. Completeness Absence of missing or null fields in critical predictive features. Ensuring essential customer address and contact numbers are imputed or populated.
4. Uniqueness Freedom from duplicate records representing the exact same event. Removing duplicate invoice rows generated by client-side browser double-clicks.
5. Validity Conformity to established domain schemas, data types, and syntax rules. Validating email formats (containing @) and date syntax (YYYY-MM-DD).
6. Integrity Referential consistency across database relationships and tables. Ensuring that every customer_id in the order table exists in the customer master table.

3. The 5 Core Pathologies of Data Cleaning

Data cleaning workflows primarily address five recurring categories of data corruption:

1 Missing Values Expected values absent from cells (NaN, None, NaT).
2 Duplicate Records Redundant duplicate observations skewing sample weights.
3 Inconsistent Data Whitespace padding, case mismatches, and mixed measurement units.
4 Incorrect Data Types Numbers or timestamps stored erroneously as raw string objects.
5 Outliers & Invalid Values Severe statistical anomalies and impossible domain violations (e.g. negative prices).

4. Missing Values: Statistical Character & Imputation

Before selecting an imputation strategy, you must diagnose why the data is missing. Modern mathematical statistics establishes three distinct mechanisms of missingness:

1. MCAR (Missing Completely At Random)

Missingness is entirely independent of both observed and unobserved data. Example: A transient network hiccup causes 3 random order packets to drop. Deleting MCAR records introduces no systematic sampling bias.

2. MAR (Missing At Random)

Missingness depends systematically on other observed features, but not on the unobserved value itself. Example: In customer surveys, younger respondents might be less likely to report household income than older respondents. Because respondent age is recorded, the missingness mechanism can be statistically modeled.

3. MNAR (Missing Not At Random)

The probability of a value being missing depends directly on the unobserved value itself. Example: High-net-worth individuals actively choosing not to report their net worth. Deleting MNAR records severely truncates distributions and induces fatal selection bias.

4.1 Auditing Missing Data in pandas

import pandas as pd
import numpy as np

# Audit raw counts and percentage missing per column
print(df.isna().sum())
missing_pct = (df.isna().mean() * 100).round(2)
print(missing_pct)

4.2 When is Row Deletion (dropna) Justified?

Dropping rows via df.dropna() or df.dropna(subset=['price']) is safe only when:

  • Missing rows comprise less than 3% to 5% of the total dataset.
  • The missingness mechanism is verified to be MCAR (Completely At Random).
  • Otherwise, dropping incomplete rows substantially reduces statistical power and skews model representations.

4.3 Imputation Strategies

Mean Imputation: Suitable only for symmetric Gaussian data; heavily distorted by outliers. df['price'].fillna(df['price'].mean())
Median Imputation (The Standard): Robust against extreme outliers and skewed financial metrics. df['price'].fillna(df['price'].median())
Mode / Categorical Imputation: Fills with the most frequent value or creates an explicit "Unknown" token. df['category'].fillna('Unknown')
scikit-learn SimpleImputer: Standard object for leak-free pipeline imputation. SimpleImputer(strategy='median')

5. Duplicate Records: Composite Keys & Smart Filtering

Duplicate rows harm predictive models by artificially doubling the gradient weight of repeated instances during optimization.

Critical Trap: Duplicate Order IDs Do Not Always Mean Duplicate Records!

In e-commerce databases, an order with order_id = 'O101' may legitimately contain multiple line items (e.g. 1 laptop and 1 mouse). Blindly running drop_duplicates(subset=['order_id']) deletes valid cart products!
Always define an explicit Composite Key (e.g., ['order_id', 'product_id']).

# 1. Audit total duplicate rows
print("Total Duplicates:", df.duplicated().sum())

# 2. View all duplicate pairs simultaneously
print(df[df.duplicated(keep=False)])

# 3. Deduplicate across a composite key, preserving the first instance
df_cleaned = df.drop_duplicates(subset=["order_id", "product", "price"], keep="first")

6. Inconsistent Data & Text Sanitization

To a machine, "Fashion", "fashion", and whitespace-padded " Fashion " are three completely distinct entities. The standard text cleaning pipeline involves:

# 1. Strip leading and trailing whitespace
df["category"] = df["category"].astype("string").str.strip()

# 2. Normalize casing to lowercase
df["category"] = df["category"].str.lower()

# 3. Map synonym variants to a canonical token
mapping = {
    "accessory": "accessories",
    "accessories": "accessories",
    "electronics": "electronics",
    "fashion": "fashion"
}
df["category"] = df["category"].map(mapping)

6.1 Sanitizing Formatted Currency Strings

When numerical prices arrive formatted as "55,000 BDT", direct float casting throws errors. We strip commas and units, then call pd.to_numeric(errors='coerce'):

df["price"] = (
    df["price"]
    .astype("string")
    .str.replace(",", "", regex=False)
    .str.replace("BDT", "", regex=False)
    .str.strip()
)
# errors="coerce" transforms unparseable entries (e.g., "N/A") cleanly into NaN
df["price"] = pd.to_numeric(df["price"], errors="coerce")

7. Data Type Casting & Domain Validation

Strict data typing enables temporal extraction and prevents silent mathematical degradation:

DateTime Conversion: Convert string dates via pd.to_datetime(df['order_date'], format='%Y-%m-%d', errors='coerce'). Invalid timestamps resolve cleanly to NaT (Not-a-Time).
Boolean Normalization: Map text indicators like "Yes" / "No" or "TRUE" / "FALSE" to native Python boolean primitives.
Domain Assertion Rules: Syntax can be valid while meaning is invalid! Assert rules such as df['price'] <= 0 or df['quantity'] < 0 to flag business rule violations.

8. Outlier Remediation: Tukey Fences & Winsorization

Engineers utilize three primary strategies for handling outliers:

1. Trimming / Dropping Used strictly when the outlier is proven to be a logging bug or corrupted typo.
2. Winsorization (Capping) Retaining the observation while clamping its value to the Upper/Lower Tukey Fence.
3. Robust Scaling Applying scikit-learn's RobustScaler to scale data using median and IQR.
winsorization_demo.py numpy + pandas
Q1 = df["quantity"].quantile(0.25)
Q3 = df["quantity"].quantile(0.75)
IQR = Q3 - Q1
lower_fence = Q1 - 1.5 * IQR
upper_fence = Q3 + 1.5 * IQR

# Capping: Clamping extreme values to the Tukey fences without deleting rows
df["quantity_capped"] = np.clip(df["quantity"], lower_fence, upper_fence)

9. Data Leakage: The Cardinal Sin in Machine Learning

During data cleaning and preprocessing, the most dangerous failure mode is Data Leakage.

Critical Warning: Never Impute or Scale Before Train/Test Splitting!

If you compute the global Mean or Median across the full combined dataset, information from the test set leaks into the training pipeline! The model appears to achieve 99% accuracy in evaluation but fails catastrophically in production.

Correct Cleaning & Imputation Lifecycle:

Raw Dataset → Train/Test Split (X_train, X_test)

→ imputer.fit_transform(X_train) (Learns median strictly from training data)

→ imputer.transform(X_test) (Applies the training median to the test set)

10. Complete Practical Python Demonstration

Here is a complete, production-grade pandas data cleaning pipeline:

complete_data_cleaning_pipeline.py pandas
import pandas as pd
import numpy as np

# 1. Synthesize noisy real-world dataset
df = pd.DataFrame({
    "order_id": ["O01", "O02", "O03", "O03", "O04", "O05"],
    "category": [" Electronics ", "electronics", "Accessories", "Accessories", "FASHION", "Fashion"],
    "price": ["55,000", "22,000", "2,500", "2,500", "1,800 BDT", "N/A"],
    "quantity": ["1", "2", "3", "3", "two", "4"],
    "order_date": ["2026-09-01", "2026-09-02", "2026-09-03", "2026-09-03", "invalid_date", "2026-09-05"]
})

# 2. Store pristine raw backup
raw_backup = df.copy(deep=True)

# 3. Text sanitization (whitespace stripping and lowercasing)
df["category"] = df["category"].astype("string").str.strip().str.lower()

# 4. Numeric field sanitization
df["price"] = df["price"].astype("string").str.replace(",", "", regex=False).str.replace("BDT", "", regex=False).str.strip()
df["price"] = pd.to_numeric(df["price"], errors="coerce")
df["quantity"] = pd.to_numeric(df["quantity"], errors="coerce")

# 5. Timestamp conversion
df["order_date"] = pd.to_datetime(df["order_date"], format="%Y-%m-%d", errors="coerce")

# 6. Deduplication on composite keys
df = df.drop_duplicates(subset=["order_id", "category", "price"], keep="first")

# 7. Imputation using robust medians
df["price"] = df["price"].fillna(df["price"].median())
df["quantity"] = df["quantity"].fillna(df["quantity"].median())

print("\n--- Cleaned DataFrame ---")
print(df)

11. Summary of Key Learnings

Defect Category Detection Method Standard Engineering Remedy
Missing Values .isna().sum() Median Imputation (numerical) or explicit Unknown tokens (categorical).
Duplicates .duplicated() Deduplication across Composite Keys via .drop_duplicates().
Inconsistent Strings .value_counts() .str.strip().str.lower() coupled with dictionary mapping.
Invalid Types .dtypes / inspection pd.to_numeric() and pd.to_datetime(errors='coerce').
Extreme Outliers Tukey IQR Fences Winsorization capping via np.clip or Robust Scaling.

Interactive Workbench: Data Cleaning Lab

Imputation Strategy Simulator, String Sanitizer, and Winsorization Outlier Sandbox

Status: 2 Missing Values Present
Order ID Product Price (BDT) Quantity
Diagnostic Insight: In the raw dataset, O03 and O05 contain missing values. Because an extreme outlier (৳250,000) exists in the price column, Mean imputation will be severely skewed. Median imputation provides the robust choice.