Handling Missing Values
Missing data means some information is absent from a dataset. Before training a model, we should first understand what is missing, why it may be missing, and how our chosen treatment could change the data.
What are Missing Values?
Missing values are data entries that are not stored properly inside a dataset. In Python and data science libraries, missing values are commonly represented as:
NaN(Not a Number)NULLNone- Empty cells
- Unknown values
Missing Data in Simple Words
Think of a school record where one student forgot to enter their age and another student's marks were not recorded. The empty cells are the missing values.
| Student | Age | Marks |
|---|---|---|
| Aman | 17 | 72 |
| Priya | Missing | 81 |
| Rohit | 18 | Missing |
| Sneha | 17 | 88 |
Why Handling Missing Values is Important
- Supports Reliable Models: Missing values can change the information available to a model, so they should be handled deliberately.
- Prevents Bias: Ignoring missing values improperly may create biased analysis.
- Avoids Compatibility Problems: Many estimators require missing values to be handled first, although some modern algorithms can work with missing values directly.
- Preserves Data Quality: Handling missing values properly keeps the dataset reliable.
- Helps Better Decision Making: Businesses rely on accurate data for forecasting and analytics.
Common Reasons & Types of Missing Values
Missing data can result from human errors, technical problems, privacy concerns, data merging issues, or data corruption.
The missingness is not related to the measured data.
The chance of missingness can be related to information we did observe.
The missingness may be related to the unobserved value itself or another unobserved reason.
Why this matters: the reason data is missing can influence whether deleting or filling values is reasonable. We should not choose an imputation method only because it is easy to code.
Check Missing Values with Python
Let's create a sample dataset and see how to check for missing values using pandas.
import pandas as pd
import numpy as np
data = {
'Name': ['Aman', 'Priya', 'Rohit', 'Sneha'],
'Age': [22, np.nan, 25, 28],
'Salary': [45000, 52000, np.nan, 61000]
}
df = pd.DataFrame(data)
print("--- Dataset ---")
print(df)
print("\n--- Count Missing Values ---")
print(df.isnull().sum())
print("\n--- Dataset Information ---")
df.info()--- Dataset ---
Name Age Salary
0 Aman 22.0 45000.0
1 Priya NaN 52000.0
2 Rohit 25.0 NaN
3 Sneha 28.0 61000.0
--- Count Missing Values ---
Name 0
Age 1
Salary 1
dtype: int64
--- Dataset Information ---
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 4 entries, 0 to 3
Data columns (total 3 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 Name 4 non-null object
1 Age 3 non-null float64
2 Salary 3 non-null float64
dtypes: float64(2), object(1)
memory usage: ...Before Choosing a Method: Measure the Missingness
First count how much data is missing. A column with 1% missing values is a different problem from a column with 70% missing values.
missing_pct = df.isna().mean() * 100
print(missing_pct.round(1))Name 0.0 Age 25.0 Salary 25.0 dtype: float64
In this four-row example, one missing value means 1 ÷ 4 × 100 = 25%. The percentage is useful, but the reason for the missing values is just as important.
Methods to Handle Missing Values
There is no single perfect method for handling missing data. The best technique depends on dataset size, the amount and pattern of missing data, the meaning of the variable, and the problem you are solving.
1. Removing Missing Values
You can remove rows or columns containing missing values, but only when the information loss is acceptable and the missingness pattern does not create unwanted bias.
- Advantages: Simple implementation, Quick cleaning
- Disadvantages: Loss of valuable data, Smaller dataset
# Remove Rows with Missing Values:
df_dropped_rows = df.dropna()
print("Dropped Rows:\n", df_dropped_rows)
# Remove Columns with Missing Values:
df_dropped_cols = df.dropna(axis=1)
print("\nDropped Columns:\n", df_dropped_cols)Dropped Rows:
Name Age Salary
0 Aman 22.0 45000.0
3 Sneha 28.0 61000.0
Dropped Columns:
Name
0 Aman
1 Priya
2 Rohit
3 Sneha2. Mean Imputation
Replace missing numerical values using the average value.
- Advantages: Easy to implement, Maintains dataset size
- Disadvantages: Sensitive to outliers
Known salaries: 45,000, 52,000, 61,000
Step 1 — Add them: 45,000 + 52,000 + 61,000 = 158,000
Step 2 — Count known values: 3
Step 3 — Divide: 158,000 ÷ 3 = 52,666.67
Result: replace Rohit's missing salary with approximately 52,666.67.
df_mean = df.copy()
df_mean['Salary'] = df_mean['Salary'].fillna(df_mean['Salary'].mean())
print(df_mean)Name Age Salary 0 Aman 22.0 45000.000000 1 Priya NaN 52000.000000 2 Rohit 25.0 52666.666667 3 Sneha 28.0 61000.000000
3. Median Imputation
Replace missing values using the median.
- Advantages: Handles outliers better, More robust than mean
Step 1 — Sort: 45,000, 52,000, 61,000
Step 2 — Choose the middle value: 52,000
Result: the median salary is 52,000.
df_median = df.copy()
df_median['Salary'] = df_median['Salary'].fillna(df_median['Salary'].median())
print(df_median)Name Age Salary 0 Aman 22.0 45000.0 1 Priya NaN 52000.0 2 Rohit 25.0 52000.0 3 Sneha 28.0 61000.0
4. Other Imputation Techniques
Beyond mean and median imputation, several smarter techniques handle special cases — categorical variables, time-series data, and trending signals.
Mode Imputation — for categorical columns
Replaces missing values with the most frequently occurring value in that column. A common simple choice for columns like City or Category where averaging makes no sense.
# Mode imputation — fills missing City with most common city df['City'] = df['City'].fillna(df['City'].mode()[0]) # Example: # Before: ['Delhi', NaN, 'Mumbai', 'Delhi', NaN] # mode()[0] = 'Delhi' # After: ['Delhi', 'Delhi', 'Mumbai', 'Delhi', 'Delhi']
Forward Fill (ffill) — for time-series data
Propagates the last known value forward to fill gaps. Useful for some ordered or time-series data when carrying the previous observation forward is a reasonable assumption.
# Forward fill — use previous row's value df = df.ffill() # Example — Daily temperature readings: # Before: [22, NaN, NaN, 25, NaN] # After: [22, 22, 22, 25, 25] # Explanation: NaN rows inherit the last valid reading above them
Backward Fill (bfill) — fill from future values
Uses the next available value to fill backward. Useful in some ordered data when using the next available observation is a defensible assumption. Avoid it when future information would create leakage in a prediction problem.
# Backward fill — use next row's value df = df.bfill() # Example — Daily temperature readings: # Before: [NaN, NaN, 22, 25, NaN] # After: [ 22, 22, 22, 25, NaN] ← last NaN stays (no future value) # Explanation: NaN rows inherit the nearest valid reading below them
Interpolation — estimate values between known points
Estimates missing numeric values from surrounding known values. Linear interpolation draws a straight-line change between known points; other methods use different assumptions. It is most sensible for ordered numeric data when values are expected to change smoothly.
# Linear interpolation — estimates a value between two known points df['Salary'] = df['Salary'].interpolate(method='linear') # Example — Annual Salary (₹ in lakhs): # Index: 0 1 2 3 4 # Before: [4.0, NaN, NaN, NaN, 8.0] # After: [4.0, 5.0, 6.0, 7.0, 8.0] # Explanation: Linear interpolation divides the gap (8.0-4.0)/4 = 1.0 # and adds 1.0 at each step → perfectly smooth ramp # Other interpolation methods: df['Salary'].interpolate(method='polynomial', order=2) # curved trend df['Salary'].interpolate(method='time') # for DatetimeIndex
✓ Advantages
Can preserve a smooth local trend · Uses neighbouring values · Useful for suitable ordered data
✗ Limitations
Depends on the chosen trend assumption · Can mislead when values jump suddenly · Not for categorical data
5. Advanced Techniques
KNN Imputation: K-Nearest Neighbors predicts missing values using similar records. It can use relationships between variables, but it is not guaranteed to outperform simple methods and can be more computationally expensive. Feature scales and the choice of neighbors also matter.
Predictive Model Imputation: Machine learning models can estimate missing values. Examples include regression-based methods and iterative multivariate imputation. These methods need careful validation because a more complex imputer is not automatically a better one.
6. Missing-Value Indicator
Sometimes the fact that a value is missing is itself useful information. You can add a simple 0/1 column before imputation.
| Salary | Salary_was_missing |
|---|---|
| 45,000 | 0 |
| Missing | 1 |
This can help a model distinguish an originally observed value from one that was filled later. Whether it helps should be checked during validation.
Choosing the Right Missing Value Technique
| Situation | Recommended Method |
|---|---|
| A small number of rows are missing and deletion is defensible | Consider removing rows |
| Numerical data with a roughly symmetric distribution | Mean may be a simple baseline |
| Categorical data with a meaningful most-common category | Mode or a separate "Missing" category |
| Ordered/time-series data with a defensible carry-forward assumption | Consider forward fill or interpolation |
| Relationships between features may help estimate missing values | Consider KNN or multivariate imputation |
Important: this table is a starting guide, not a fixed rule. Compare reasonable methods using validation and domain knowledge.
Complete Python Example
import pandas as pd
import numpy as np
data = {
'Age': [22, 25, np.nan, 30, 28],
'Salary': [45000, np.nan, 52000, 61000, np.nan]
}
df = pd.DataFrame(data)
print("--- Missing Values Count ---")
print(df.isnull().sum())
# Impute Operations
df['Age'] = df['Age'].fillna(df['Age'].median())
df['Salary'] = df['Salary'].fillna(df['Salary'].mean())
print("\n--- Dataset After Handling Missing Values ---")
print(df)--- Missing Values Count ---
Age 1
Salary 2
dtype: int64
--- Dataset After Handling Missing Values ---
Age Salary
0 22.0 45000.000000
1 25.0 52666.666667
2 26.5 52000.000000
3 30.0 61000.000000
4 28.0 52666.666667For a real ML project: split the data first. Calculate the median, mean, or other imputation rule using the training data only, then apply that learned rule to validation and test data. This helps avoid data leakage.
Best Practices & Common Mistakes
Best Practices
- Analyze missing value percentage first
- Understand why data is missing
- Use visualization tools
- Test multiple methods
- Validate model performance
- Fit imputation statistics on training data, then apply them to validation/test data
Common Mistakes
- Blindly removing data
- Using mean for skewed data
- Ignoring missing value patterns
- Applying one method everywhere
Poor handling can distort distributions, hide important patterns, or create data leakage. Some estimators reject missing values while others can handle them directly, so always check the algorithm and validate the preprocessing choice.
Common Questions
Should I always replace missing values?
No. Sometimes deletion is reasonable, sometimes imputation is better, and some algorithms can work with missing values directly. The choice depends on the data and the model.
Mean or median — which is better?
Mean is a simple baseline for roughly symmetric numeric data. Median is often more robust when extreme values or skew are present.
Why should imputation be fitted only on training data?
Using validation or test data to calculate an imputation value lets information from those sets leak into training. Fit the preprocessing on the training set, then apply it to the other sets.
Missing values are only one preprocessing step. Next, learn how to convert text categories into numbers in Encoding Categorical Data. You can also revisit Exploratory Data Analysis to learn how missingness is discovered during data investigation.