Data Cleaning With Pandas – Extended
1. Introduction:
What Is Data Cleaning?
Data cleaning is the process of detecting, correcting, or removing inaccurate, incomplete, corrupted, inconsistent, and irrelevant data from a dataset.
In any data project—analytics, BI, ML, or AI—clean data contributes ~80% of the model’s success. Without clean data, even the best model will fail.
Common Data Problems
- Missing values
- Duplicate rows
- Outliers and impossible values
- Wrong data types
- Inconsistent formatting
- Noisy text (spaces, typos, casing issues)
- Categorical inconsistencies
- Mixed units (kg vs lbs)
- Irregular date formats
Pandas provides powerful tools to handle these problems.
2. Understanding Data
import pandas as pd
df = pd.read_csv("sample.csv") # Loading data
# Preview Dataset
df.head()
df.tail()
df.sample(5)
## Understand Structure
df.info()
df.describe(include='all')
df.shape
df.columns
# Detect Data Types
df.dtypes
3. Handling Missing Data
1. Identify Missing Values
df.isna().sum()
df.isnull().mean() * 100 # percentage
2. Remove Missing Data
df_clean = df.dropna()
df_clean = df.dropna(subset=['age', 'salary'])
df_clean = df.dropna(thresh=3) # rows with at least 3 non-null values
3. Fill Missing Values
# Fill with Mean / Median / Mode
df['age'] = df['age'].fillna(df['age'].mean())
df['salary'] = df['salary'].fillna(df['salary'].median())
df['gender'] = df['gender'].fillna(df['gender'].mode()[0])
# Forward & Backward Fill
df['sales'].fillna(method='ffill', inplace=True)
df['sales'].fillna(method='bfill', inplace=True)
# Fill using interpolation
df['temperature'] = df['temperature'].interpolate()
4. Handling Duplicates
# Check duplicates
df.duplicated().sum()
# Remove duplicates
df = df.drop_duplicates()
# Remove duplicates based on specific columns
df = df.drop_duplicates(subset=['name', 'date'])
6. Fixing Incorrect Data Types
# Convert to numeric
df['age'] = pd.to_numeric(df['age'], errors='coerce')
# Convert to integer
df['age'] = df['age'].astype('Int64')
# Convert to datetime
df['date'] = pd.to_datetime(df['date'], errors='coerce')
# Convert categorical
df['gender'] = df['gender'].astype('category')
7. Text & String Cleaning
# Basic Text Cleaning
df['name'] = df['name'].str.strip()
df['name'] = df['name'].str.lower()
df['name'] = df['name'].str.replace(r'[^a-zA-Z ]', '', regex=True)
# Fix Inconsistent Categories
df['city'] = df['city'].str.title()
df['city'].replace({'Ktm': 'Kathmandu', 'KTM': 'Kathmandu'}, inplace=True)
# Extracting With Regex
df['year'] = df['text'].str.extract(r'(\d{4})')
8. Handling Inconsistent Data
# Detect impossible values
df[df['age'] < 0]
df[df['salary'] < 0]
df[df['height'] > 250]
# Fix values
df.loc[df['age'] < 0, 'age'] = df['age'].median()
9. Feature Engineering
# Create new columns
df['total_price'] = df['quantity'] * df['unit_price']
# Binning
df['age_group'] = pd.cut(df['age'], bins=[0,18,40,60,100],
labels=['Teen','Adult','Middle','Senior'])
# Encoding categorical variables
df = pd.get_dummies(df, columns=['gender', 'city'])
# Date features
df['year'] = df['date'].dt.year
df['month'] = df['date'].dt.month
df['weekday'] = df['date'].dt.day_name()
10. Renaming Columns
# Best practice
df.columns = df.columns.str.lower().str.replace(' ', '_')
# Manual renaming
df.rename(columns={'Sale Price': 'sale_price'}, inplace=True)
11. Scaling & Normalization
# Min-Max Scaling
from sklearn.preprocessing import MinMaxScaler
scaler = MinMaxScaler()
df[['salary_scaled']] = scaler.fit_transform(df[['salary']])
# Standard Scaling
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
df[['salary_z']] = scaler.fit_transform(df[['salary']])
12. End-to-End Example (Complete Walkthrough)
data = {
'name': ['Ram ', 'Shyam', 'Hari', None, 'SITA'],
'age': ['25', '30', None, '40', '-5'],
'salary': [20000, 25000, None, 40000, 15000],
'city': ['ktm', 'KTM', 'pokhara', 'Biratnagar', None],
'join_date': ['2020/01/01', '2021/05/03', None, '2019/12/15', '2021/01/20']
}
df = pd.DataFrame(data)
# Step 1: Clean Text
df['name'] = df['name'].str.strip().str.title()
# Step 2: Fix Data Types
df['age'] = pd.to_numeric(df['age'], errors='coerce')
df['join_date'] = pd.to_datetime(df['join_date'], errors='coerce')
# Step 3: Handle Missing Values
df['age'] = df['age'].fillna(df['age'].median())
df['salary'] = df['salary'].fillna(df['salary'].median())
df['city'] = df['city'].fillna('Unknown')
# Step 4: Correct Incorrect Values**
df.loc[df['age'] < 0, 'age'] = df['age'].median()
# Step 5: Fix Categorical Inconsistency
df['city'] = df['city'].str.title()
df['city'].replace({'Ktm': 'Kathmandu', 'Ktm ': 'Kathmandu', \
'KTM': 'Kathmandu'}, inplace=True)
# Step 6: Feature Engineering
df['year_joined'] = df['join_date'].dt.year
df['salary_lakh'] = df['salary'] / 100000
Output:
Uncleaned data:
name age salary city join_date
0 Ram 25 20000.0 ktm 2020/01/01
1 Shyam 30 25000.0 KTM 2021/05/03
2 Hari None NaN pokhara None
3 None 40 40000.0 Biratnagar 2019/12/15
4 SITA -5 15000.0 None 2021/01/20
Cleaned data:
name age salary city join_date year_joined salary_lakh
0 Ram 25.0 20000.0 Kathmandu 2020-01-01 2020.0 0.200
1 Shyam 30.0 25000.0 Kathmandu 2021-05-03 2021.0 0.250
2 Hari 27.5 22500.0 Pokhara NaT NaN 0.225
3 None 40.0 40000.0 Biratnagar 2019-12-15 2019.0 0.400
4 Sita 27.5 15000.0 Unknown 2021-01-20 2021.0 0.150
Result
A clean dataset ready for:
- EDA
- Visualization
- Machine learning
- Storage
13. Summary & Best Practices
Data Cleaning Checklist
- Understand data structure
- Handle missing values
- Fix data types
- Remove duplicates
- Address outliers
- Correct inconsistent values
- Clean text fields
- Standardize categories
- Engineer meaningful features
Best Practices
- Clean before modeling
- Never drop data blindly
- Use visualizations to detect issues
- Automate cleaning for repeated tasks
- Document every step