Lesson 66 · Data Science 50–60 minutes Intermediate

Data Cleaning

Learn how to transform messy, incomplete and inconsistent datasets into reliable data ready for analysis. This lesson covers missing values, duplicate records, incorrect data types, text cleaning, dates, outliers, validation and professional data-cleaning workflows using Pandas.

0%
01

Learning Objectives

Data cleaning is one of the most important practical skills for a data analyst. Real-world datasets often contain missing, duplicated, incorrectly formatted or inconsistent information.

You will learn how to:

  • Understand what data cleaning means.
  • Inspect an unfamiliar dataset.
  • Identify missing values.
  • Remove or replace missing data.
  • Detect and remove duplicates.
  • Correct incorrect data types.
  • Clean inconsistent text values.
  • Standardize column values.
  • Convert dates correctly.
  • Clean numeric values.
  • Identify potential outliers.
  • Validate business rules.
  • Rename columns professionally.
  • Use conditional transformations.
  • Use apply() when appropriate.
  • Build a repeatable cleaning workflow.
02

What Is Data Cleaning?

Data cleaning is the process of detecting and correcting inaccurate, incomplete, duplicated, inconsistent or improperly formatted data.

Consider the following customer dataset:

Name       Age       City
Ali        25        Lahore
ali        25        lahore
Sara       NaN       Islamabad
Ahmed      "31"      ISB

The data contains several problems:

  • Different capitalization.
  • A duplicated customer.
  • A missing age.
  • Age stored as text.
  • Different representations of Islamabad.

Clean Data

The goal is not simply to make a dataset look better. The goal is to make the data accurate, consistent and suitable for the intended analysis.

03

Why Data Cleaning Matters

Poor-quality data can produce poor-quality analysis.

Bad Data
   ↓
Incorrect Calculations
   ↓
Incorrect Analysis
   ↓
Incorrect Decisions

For example, if a sales dataset contains duplicate transactions, the calculated revenue may be higher than the actual revenue.

Important Principle

Never blindly modify data. First understand what the data represents and why an unusual value exists.

04

Professional Data Cleaning Workflow

A professional cleaning process usually follows a structured workflow.

1. Load Data
      ↓
2. Inspect Data
      ↓
3. Identify Problems
      ↓
4. Clean Data
      ↓
5. Validate Data
      ↓
6. Analyze Data
      ↓
7. Export Clean Dataset

Think Before You Clean

Data cleaning is not just a collection of Pandas commands. It is a reasoning process. You must understand what each column represents before deciding how to modify it.

05

Inspecting Data

Before changing anything, inspect the dataset.

import pandas as pd

df = pd.read_csv(
    "sales.csv"
)

print(df.head())

print(df.shape)

print(df.columns)

print(df.info())

print(df.describe())

You should investigate:

  • Number of rows.
  • Number of columns.
  • Column names.
  • Data types.
  • Missing values.
  • Unexpected values.
  • Duplicate records.
06

Finding Missing Values

Missing values are extremely common in real-world datasets.

print(df.isna())

To count missing values in each column:

print(
    df.isna().sum()
)

To calculate the percentage of missing values:

missing_percentage = (
    df.isna().mean() * 100
)

print(missing_percentage)

Why Percentage Matters

Knowing that a column has 100 missing values is useful, but knowing that those 100 values represent 1% or 80% of the dataset provides much more context.

07

Removing Missing Data

Pandas provides dropna() for removing rows or columns containing missing values.

cleaned = df.dropna()

print(cleaned)

You can remove rows only when specific columns are missing.

cleaned = df.dropna(
    subset=["CustomerID"]
)

You can also remove columns containing missing values, although this should be done carefully.

cleaned = df.dropna(
    axis=1
)

Do Not Delete Automatically

Removing missing rows may also remove valuable information. Always determine why values are missing before deleting them.

08

Filling Missing Values

Instead of deleting missing values, you can replace them with appropriate values.

df["Age"] = df[
    "Age"
].fillna(0)

For numerical data, the mean or median may sometimes be useful.

median_age = df[
    "Age"
].median()

df["Age"] = df[
    "Age"
].fillna(median_age)

For categorical data, a common strategy is to use the most frequent value or an explicit category such as "Unknown".

df["City"] = df[
    "City"
].fillna("Unknown")

Choose Based on Context

There is no universal replacement value for every missing field. The correct approach depends on the meaning and distribution of the data.

09

Detecting Duplicate Records

Duplicate rows can lead to incorrect calculations.

duplicates = df.duplicated()

print(duplicates)

Count duplicates:

print(
    df.duplicated().sum()
)

Remove complete duplicate rows:

df = df.drop_duplicates()

You can also identify duplicates based on specific columns.

df.duplicated(
    subset=["CustomerID"]
)
10

Correcting Data Types

A dataset may contain numbers stored as strings, dates stored as text or inconsistent types.

print(df.dtypes)

Convert a column to numeric data:

df["Price"] = pd.to_numeric(
    df["Price"],
    errors="coerce"
)

With errors="coerce", values that cannot be converted become missing values.

df["Quantity"] = df[
    "Quantity"
].astype("Int64")

Check Before Converting

Always inspect unusual values before converting them. A value such as "1,200" may require additional cleaning before numeric conversion.

11

Cleaning Text Data

Text fields frequently contain extra spaces, inconsistent capitalization and formatting problems.

df["Name"] = df[
    "Name"
].str.strip()

Convert text to lowercase:

df["City"] = df[
    "City"
].str.lower()

Convert text to uppercase:

df["Code"] = df[
    "Code"
].str.upper()

Capitalize words:

df["City"] = df[
    "City"
].str.title()

Example

"  Lahore "
"LAHORE"
"lahore"
"Lahore "

These values may represent the same city but are not textually identical.

12

Replacing Values

Use replace() when values need to be standardized.

df["City"] = df[
    "City"
].replace({
    "ISB": "Islamabad",
    "LHR": "Lahore"
})

You can also replace individual values:

df["Status"] = df[
    "Status"
].replace(
    "Completed ",
    "Completed"
)

Combining replacement with string cleaning can create a more reliable standardization process.

13

Cleaning Dates

Dates are often imported as strings and need to be converted before analysis.

df["OrderDate"] = pd.to_datetime(
    df["OrderDate"],
    errors="coerce"
)

Once converted, you can extract useful components.

df["Year"] = (
    df["OrderDate"].dt.year
)

df["Month"] = (
    df["OrderDate"].dt.month
)

df["Day"] = (
    df["OrderDate"].dt.day
)

Why Dates Matter

Correctly formatted dates allow you to perform time-based analysis such as monthly sales, yearly revenue and daily trends.

14

Cleaning Numeric Data

Numeric fields can contain currency symbols, commas, spaces or other characters.

prices = pd.Series([
    "$1,200",
    "$850",
    "$2,500"
])

prices = (
    prices
    .str.replace("$", "", regex=False)
    .str.replace(",", "", regex=False)
    .astype(float)
)

print(prices)

Output

0    1200.0
1     850.0
2    2500.0
dtype: float64

Numeric cleaning is particularly important when data comes from manually maintained spreadsheets or exported reports.

15

Understanding Outliers

An outlier is a value that is unusually different from other observations.

sales = pd.Series([
    100,
    120,
    110,
    105,
    115,
    5000
])

print(
    sales.describe()
)

The value 5000 is dramatically larger than the other values.

Outlier Does Not Automatically Mean Error

A large value could be a data-entry mistake, but it could also represent a legitimate large transaction. Investigate before removing it.

Simple Statistical Approach

One common technique uses the interquartile range (IQR).

q1 = sales.quantile(0.25)

q3 = sales.quantile(0.75)

iqr = q3 - q1

lower = q1 - 1.5 * iqr

upper = q3 + 1.5 * iqr

outliers = sales[
    (sales < lower) |
    (sales > upper)
]

print(outliers)

This is a useful analytical technique, but the appropriate outlier method depends on the dataset and business problem.

16

Data Validation

Cleaning should be followed by validation.

Suppose product quantity must always be greater than zero.

invalid = df[
    df["Quantity"] <= 0
]

print(invalid)

Validate prices:

invalid_prices = df[
    df["Price"] < 0
]

Validate categories:

valid_categories = [
    "Electronics",
    "Clothing",
    "Home"
]

invalid = df[
    ~df["Category"].isin(
        valid_categories
    )
]

Cleaning + Validation

Cleaning changes problematic data. Validation checks whether the resulting dataset satisfies the rules required for analysis.

17

Cleaning Column Names

Consistent column names make analytical code easier to understand and maintain.

df.columns = (
    df.columns
    .str.strip()
    .str.lower()
    .str.replace(" ", "_")
)

print(df.columns)

For example:

Customer Name
Order Date
Total Sales

can become:

customer_name
order_date
total_sales

Professional Convention

Snake case such as customer_name and order_date is a common and readable convention for Python-oriented data workflows.

18

Standardizing Data

Standardization means representing equivalent values consistently.

df["Gender"] = df[
    "Gender"
].replace({
    "M": "Male",
    "m": "Male",
    "F": "Female",
    "f": "Female"
})

Another example:

df["Payment"] = df[
    "Payment"
].str.strip().str.title()

This can turn values such as:

" cash "
"Cash"
"cash"
"CASH"

into a consistent representation.

19

Conditional Cleaning

Sometimes the correct cleaning rule depends on a condition.

df.loc[
    df["Age"] < 0,
    "Age"
] = None

You can also create standardized categories.

df["CustomerType"] = "Regular"

df.loc[
    df["TotalSales"] >= 5000,
    "CustomerType"
] = "Premium"

This approach is useful when business rules are known and clearly defined.

20

Using apply()

apply() allows you to apply a function to values in a Series or along a DataFrame axis.

def clean_name(name):
    return name.strip().title()

df["Name"] = df[
    "Name"
].apply(clean_name)

For simple operations, built-in vectorized Pandas methods are often preferable because they are generally clearer and can be more efficient.

df["Name"] = df[
    "Name"
].str.strip().str.title()

Good Practice

Use apply() when you genuinely need custom row-by-row or value-by-value logic. Do not automatically use it for operations that Pandas already provides directly.

21

Keep the Raw Data Safe

A professional data workflow should preserve the original dataset.

raw_df = pd.read_csv(
    "sales.csv"
)

df = raw_df.copy()

Perform cleaning on df while keeping raw_df unchanged.

df["Name"] = (
    df["Name"]
    .str.strip()
    .str.title()
)

Professional Principle

Keep a clear separation between raw data, cleaned data and analytical outputs whenever practical. This makes the workflow easier to audit and repeat.

22

Practical Example — Cleaning Ecommerce Data

Consider this intentionally messy ecommerce dataset.

import pandas as pd

df = pd.DataFrame({
    "Customer Name": [
        " ali ",
        "Sara",
        "Ahmed",
        "Ali"
    ],

    "City": [
        "lahore",
        "ISB",
        " Islamabad ",
        "Lahore"
    ],

    "Price": [
        "$1,200",
        "$800",
        "$500",
        "$1,200"
    ],

    "Quantity": [
        "2",
        "3",
        "1",
        "2"
    ]
})

print(df)

Step 1 — Clean Column Names

df.columns = (
    df.columns
    .str.strip()
    .str.lower()
    .str.replace(" ", "_")
)

Step 2 — Clean Customer Names

df["customer_name"] = (
    df["customer_name"]
    .str.strip()
    .str.title()
)

Step 3 — Standardize Cities

df["city"] = (
    df["city"]
    .str.strip()
    .str.title()
)

df["city"] = df[
    "city"
].replace({
    "Isb": "Islamabad"
})

Step 4 — Clean Prices

df["price"] = (
    df["price"]
    .str.replace("$", "", regex=False)
    .str.replace(",", "", regex=False)
    .astype(float)
)

Step 5 — Convert Quantity

df["quantity"] = pd.to_numeric(
    df["quantity"],
    errors="coerce"
)

Step 6 — Calculate Revenue

df["revenue"] = (
    df["price"] *
    df["quantity"]
)

Step 7 — Validate

print(df.info())
print(df.isna().sum())
print(df.duplicated().sum())

Final Workflow

Raw Ecommerce Data
        ↓
Column Cleaning
        ↓
Text Standardization
        ↓
Numeric Conversion
        ↓
Validation
        ↓
Calculated Revenue
        ↓
Analysis Ready
23

Common Data Cleaning Mistakes

Mistake 1 — Deleting Missing Rows Immediately

Missing values may contain important information. Investigate first.

Mistake 2 — Removing Every Outlier

An unusual value may be a legitimate transaction. Do not assume that unusual means incorrect.

Mistake 3 — Modifying the Original Dataset

Always consider preserving a raw copy so your cleaning decisions can be reviewed later.

Mistake 4 — Ignoring Data Types

A number stored as text can cause incorrect calculations or prevent analytical operations.

Mistake 5 — Cleaning Without Understanding the Data

A technically correct Pandas operation can still produce a logically incorrect dataset if the business meaning is misunderstood.

24

Practice Exercises

Exercise 1 — Missing Values

Create a DataFrame containing missing ages and salaries. Detect the missing values and calculate their percentages.

Exercise 2 — Duplicate Records

Create duplicate customer records. Detect and remove the duplicates.

Exercise 3 — Clean Text

Clean a column containing values such as " lahore ", "LAHORE" and "Lahore".

Exercise 4 — Currency

Convert values such as "$1,500" into numerical values.

Exercise 5 — Dates

Convert an order-date column into a proper datetime column and extract the month and year.

Exercise 6 — Validation

Find all records where price or quantity is less than zero.

25

Mini Challenge — Real-World Sales Data Cleaner

Your company has received a messy sales report. Before the data can be analyzed, you must clean it.

Your Mission

  1. Clean the column names.
  2. Remove leading and trailing spaces.
  3. Standardize customer names.
  4. Standardize city names.
  5. Convert prices to numbers.
  6. Convert quantities to numbers.
  7. Detect missing values.
  8. Detect duplicate records.
  9. Remove genuine duplicates.
  10. Validate that prices are not negative.
  11. Validate that quantities are greater than zero.
  12. Create a revenue column.
  13. Save the cleaned dataset as a CSV file.

Starter Dataset

import pandas as pd

sales = pd.DataFrame({
    " Customer Name ": [
        " ali ",
        "Sara",
        "AHMED",
        "Ali"
    ],

    " City ": [
        "lahore",
        "ISB",
        " Islamabad ",
        "Lahore"
    ],

    " Price ": [
        "$1,200",
        "$800",
        "$500",
        "$1,200"
    ],

    " Quantity ": [
        "2",
        "3",
        "1",
        "2"
    ]
})

print(sales)

Suggested Cleaning Pipeline

# Preserve raw data
raw_sales = sales.copy()

# Clean column names
sales.columns = (
    sales.columns
    .str.strip()
    .str.lower()
    .str.replace(" ", "_")
)

# Clean names
sales["customer_name"] = (
    sales["customer_name"]
    .str.strip()
    .str.title()
)

# Clean cities
sales["city"] = (
    sales["city"]
    .str.strip()
    .str.title()
)

sales["city"] = sales[
    "city"
].replace({
    "Isb": "Islamabad"
})

# Clean prices
sales["price"] = (
    sales["price"]
    .str.replace("$", "", regex=False)
    .str.replace(",", "", regex=False)
)

sales["price"] = pd.to_numeric(
    sales["price"],
    errors="coerce"
)

# Convert quantity
sales["quantity"] = pd.to_numeric(
    sales["quantity"],
    errors="coerce"
)

# Calculate revenue
sales["revenue"] = (
    sales["price"] *
    sales["quantity"]
)

print(sales)

Professional Extension

Add validation rules and create a final cleaned file.

invalid = sales[
    (sales["price"] < 0) |
    (sales["quantity"] <= 0)
]

print("Invalid records:")
print(invalid)

sales.to_csv(
    "clean_sales.csv",
    index=False
)

Think of this final CSV as the dataset you would hand to a data analyst or load into a BI tool.

26

Knowledge Check

1. What is data cleaning?

2. Which method detects missing values?

3. Which method removes duplicate rows?

4. What is fillna() used for?

5. What does pd.to_numeric() help with?

6. Why might str.strip() be useful?

7. What is an outlier?

8. Should every outlier be deleted?

9. Why preserve a raw dataset?

10. What should follow data cleaning?

27

Lesson Summary

Data cleaning is a critical part of professional data analysis. Before generating charts, calculating KPIs or building dashboards, analysts need confidence that the underlying data is reliable.

What You Learned

  • Data cleaning prepares raw data for reliable analysis.
  • Always inspect data before modifying it.
  • Missing values can be detected using isna().
  • dropna() can remove missing records.
  • fillna() can replace missing values.
  • Duplicate records can be detected and removed.
  • Data types should be appropriate for the intended analysis.
  • Text values often require trimming and standardization.
  • Dates should be converted into proper datetime values.
  • Currency and numeric fields may require additional cleaning.
  • Outliers should be investigated rather than automatically deleted.
  • Business rules can be used to validate data.
  • Consistent column names improve maintainability.
  • apply() can handle custom transformations when appropriate.
  • Raw data should generally be preserved.
  • Cleaning should be followed by validation.

You have now covered a complete foundation for preparing real-world datasets with Python and Pandas. The next lesson moves into Matplotlib, where you will turn cleaned data into meaningful visualizations and charts.

Ready to Continue?

You have completed the Data Cleaning lesson.