Based on the MLS-C01 exam guideReport an error
fillna(mean) is safe only under MCAR.transform to validation and test.The first step of exploratory data analysis (EDA) is "making the data clean." Domain 2 (Exploratory Data Analysis) of MLS-C01 accounts for about 24% of the exam, and data cleaning sits at its center. No matter how good the model, if you feed it data mixed with missing values, outliers, and duplicates, it is "garbage in, garbage out."
Before handling missing values, you need to know why they are missing. Statistics divides missingness mechanisms into three kinds.
| Mechanism | Meaning | Example | Consequence of simple deletion |
|---|---|---|---|
| MCAR (Missing Completely At Random) | Missingness is completely random, unrelated to other variables | Random gaps caused by a sensor malfunction | Almost no bias |
| MAR (Missing At Random) | Missingness depends on other observed variables | High earners refuse to answer the income question more often | Can be corrected by using other variables |
| MNAR (Missing Not At Random) | Missingness depends on the value itself | People with very low credit scores hide their score | Severe bias |
The missingness mechanism classification (MCAR/MAR/MNAR) is a framework proposed by the statistician Donald Rubin in 1976. The key insight is that "the validity of missing-value handling depends on why the values are missing." Simple mean imputation is unbiased only under the MCAR assumption, and applying it to MNAR data distorts the distribution. That is why visualizing the missingness pattern (for example, a missingness heatmap) before blindly using fillna(mean) is the standard practice of EDA.
Handling missing values broadly splits into deletion and imputation.
| Strategy | Method | Suitable when | Risk |
|---|---|---|---|
| Row deletion (listwise) | Remove rows that have missing values | Missing rate is very low and MCAR | Data loss, sample bias |
| Mean/median imputation | Fill numeric missing values with a statistic | Quick baseline | Reduced variance, distorted correlations |
| Mode imputation | Fill categorical missing values with the most frequent category | Categorical | Over-representation of the majority category |
| KNN imputation | Estimate from neighbors' values | Correlation between variables exists | Computation cost, sensitive to scale |
| Model-based imputation | Predict with regression/MICE | MAR, strong relationships between variables | Complexity, overfitting risk |
| Add indicator variable | Create a "was missing" flag column | MNAR, missingness itself is a signal | Increased dimensionality |
import pandas as pd
from sklearn.impute import SimpleImputer, KNNImputer
df = pd.read_csv("raw/customers.csv")
# Numeric: median imputation (robust to outliers)
num_imputer = SimpleImputer(strategy="median")
df[["age", "income"]] = num_imputer.fit_transform(df[["age", "income"]])
# Categorical: mode imputation
cat_imputer = SimpleImputer(strategy="most_frequent")
df[["region"]] = cat_imputer.fit_transform(df[["region"]])
# Use KNN imputation if inter-variable correlation is strong
knn_imputer = KNNImputer(n_neighbors=5)
df_num = pd.DataFrame(knn_imputer.fit_transform(df.select_dtypes("number")))MICE (Multiple Imputation by Chained Equations) repeatedly regresses each variable with missing values on the other variables, capturing even the "uncertainty of imputation" that single imputation ignores. Multiple imputation corrects the problem where mean imputation artificially shrinks variance and makes confidence intervals too narrow. At the exam level, it is enough to understand that "if relationships between variables are strong, KNN or model-based imputation is more accurate than simple imputation."
⚠️ Pitfall: Imputation must be fit on the training data only, and its statistics applied to validation and test. If you compute the mean over the entire data, test information leaks into training, producing data leakage and inflated performance. This is why scikit-learn uses
fit_transformon the training set and onlytransformon the test set.
An outlier is a value that deviates greatly from other observations. It may be an input error or a genuinely rare event, so you must not remove it indiscriminately.
| Method | Criterion | Distribution assumption | Robustness | Notes |
|---|---|---|---|---|
| Z-score | How many standard deviations from the mean. By convention |z| > 3 | Assumes normal distribution | Weak | Outliers shake the mean and standard deviation |
| IQR | Below Q1 − 1.5×IQR, above Q3 + 1.5×IQR | None | Strong | Safe even for skewed distributions |
| Visualization | Box plot, scatter plot, histogram | None | — | Check context with your own eyes |
| Model-based | Isolation Forest, DBSCAN, LOF | None | Strong | Can detect multivariate outliers |
| Random Cut Forest | SageMaker built-in anomaly score | None | Strong | Suited for streaming and large scale |
import numpy as np
# IQR-based outlier boundaries
Q1 = df["income"].quantile(0.25)
Q3 = df["income"].quantile(0.75)
IQR = Q3 - Q1
lower, upper = Q1 - 1.5 * IQR, Q3 + 1.5 * IQR
# Winsorizing: clip to the boundaries (preserve instead of delete)
df["income"] = df["income"].clip(lower, upper)| Treatment | Description | Suitable when |
|---|---|---|
| Delete | Remove outlier rows | Clear input errors |
| Winsorizing/clipping | Replace with boundary values | You want to keep them but reduce the impact of extremes |
| Transform | Compress with log or square root | Distributions with a long right tail |
| Keep | Leave as is | When outliers are the target (fraud detection) |
| Separate modeling | A model that handles outliers separately | The anomaly detection problem itself |
The reason IQR is more robust than Z-score is the concept of the breakdown point. The mean and standard deviation are shaken by a single outlier (breakdown point 0%), but the median and quartiles remain stable even if up to 25% of the data is contaminated. The tool that detects outliers must not itself be swayed by outliers, so robust statistics (median, IQR) are preferred. In problems like fraud detection or anomaly detection where the outliers are the answer, the key is not removal but "learning those outliers."
⚠️ Pitfall: If you memorize "outlier = something to remove," you will definitely get fraud-detection questions wrong. If the passage mentions "fraud," "equipment failure," or "anomaly detection," extreme values are signals to be caught.
The last "dirt" is duplicate rows and logic errors.
# Remove complete duplicates
df = df.drop_duplicates()
# Duplicates by key (keep the latest record)
df = df.sort_values("updated_at").drop_duplicates(subset=["user_id"], keep="last")
# Filter logic errors
df = df[(df["age"] >= 0) & (df["age"] <= 120)][Wrong order] split → remove duplicates
Records of the same user scattered across training and validation sets → leakage → inflated performance
[Correct order] clean duplicates/keys → split → impute/scale (fit on training set)
If you remove duplicates only right before model training, then after the split the same record is scattered across the training and validation sets and causes leakage. Especially for time series or user-level data, you must finish removing duplicates and cleaning keys before the split for the evaluation to be honest.
Even for the same cleaning, the tool differs by scale and user.
| Tool | Nature | When to choose |
|---|---|---|
| SageMaker Data Wrangler | Visual preparation + data quality and insights report | Quickly diagnosing and cleaning with no code and exporting the flow |
| AWS Glue DataBrew | No-code cleaning recipes | Data analysts building cleaning rules without code |
| SageMaker Processing | Code-based distributed preprocessing job | Large-scale processing with custom logic |
| AWS Glue ETL | Serverless Spark | Shared cleaning across the data lake |
| Amazon EMR | Full-control cluster | Petabyte scale, fine-grained tuning needed |
Cleaning by hand in a notebook and then saving only the resulting CSV cannot be reproduced. You become unable to answer "why did this model work well back then?"
Before choosing a cleaning method, you must look at the data first. Here is the checklist, in order.
If you fill a column with a very high missing rate using the mean, almost every row gets the same value, creating a column with no information. In that case, dropping the column or a "was missing" flag is more honest.
You encounter missing values
├─ Missing rate is overwhelmingly high (e.g., 90%+) → drop the column, or keep only a "was missing" flag
├─ Missingness itself is a signal (MNAR) → add indicator variable + impute
├─ Strong correlation with other variables (MAR) → KNN / model-based imputation
└─ Looks random and the rate is low (MCAR) → median (skewed) / mean (symmetric) / mode (categorical)
You encounter outliers
├─ Clear input error → delete or apply a logic filter
├─ Distribution has a long right tail → log transform
├─ Just want to reduce the impact of extremes → winsorizing (clipping)
└─ Outliers are the answer → keep, approach as an anomaly detection problem
In cleaning, order equals correctness.
fit on the training set, transform for the rest.In the next article we cover feature engineering (scaling, encoding, binning), which transforms the cleaned data so the model learns it well.
Click a choice to reveal the answer and explanation.
Question 1
An income variable that is long-tailed to the right (right-skewed) has missing values. What is the safest choice when building a baseline with simple imputation?
Question 2
While building a fraud detection model, you find many extremely large values in the transaction amounts. What is the most appropriate attitude toward these outliers?
Question 3
What is the correct way to avoid data leakage when applying mean imputation of missing values with scikit-learn?
Question 4
The data does not follow a normal distribution, and you want to detect outliers without distributional assumptions. Which method is most appropriate?
Question 5
In user-level data, what is the most correct time to clean up duplicate records?