Unit 2 • Lesson 1

What Dirty Data Looks Like

Overview

The four problems you will meet in almost every real file.

Beginner 20–25 min

What You Will Learn in This Lesson

By the end of this lesson, you will be able to:

  • Name the four problems that turn up in almost every real data file.
  • Explain why each one produces a wrong answer rather than an error.
  • Inspect a column with set and a count before summarising it.
  • Write a small report of what is wrong with a table.

Why This Matters

A crash tells you where to look. Dirty data does not crash: a blank score, a number stored as text, a student entered twice all flow through to an average that looks exactly as trustworthy as a correct one. Learning to look before you summarise is the habit that separates an analysis you can defend from one that is merely confident — and it costs a few lines.

Step 1: Four recurring problems

Almost every file you will ever clean has some mix of the same four faults.

1

Missing values and wrong types

A missing value is a blank, or a marker like "n/a", where a value should be. A wrong type is a number stored as text, which is every number read from a file until you convert it. Both break arithmetic, and some of those breaks are silent.

rows = [
    {"name": "Ada", "score": "92"},
    {"name": "Grace", "score": ""},
    {"name": "Alan", "score": "n/a"},
]
for r in rows:
    print(repr(r["score"]))
2

Duplicates and inconsistent spellings

A duplicate is the same record twice, often from a file being appended to more than once. An inconsistent spelling is the same value written several ways — "Maths", "maths", " maths" — which a computer counts as three different things.

subjects = ["Maths", "maths", " maths", "Computing"]
print(len(set(subjects)), "distinct values for what is really 2 subjects")

Mini Practice #1: Spot the four

Try It Yourself

Print the distinct values of subject and of score. Which of the four problems can you see?

Press Run to see output

Step 2: Why they are dangerous

The problem is not that dirty data is hard to work with. It is that it is easy to work with and wrong.

1

A wrong answer that looks right

A duplicated row is counted twice. Nothing about the resulting average tells you so.

scores = [92, 88, 79, 92]   # Ada entered twice
print(round(sum(scores) / len(scores), 1))

clean = [92, 88, 79]
print(round(sum(clean) / len(clean), 1))
2

Text that adds

Adding two strings does not raise — it joins them. A total computed over a text column is a long string of digits, and if it is then printed next to a label it can look like a number.

scores = ["92", "88"]
total = scores[0] + scores[1]
print("total:", total)

Step 3: Look before you summarise

Three cheap looks catch most of the four problems.

1

The distinct values in a column

set(column) collapses a column to the values that actually occur. Blanks, markers and spelling variants all show up at once.

subjects = ["maths", "Maths", "art", "", "art", "n/a"]
print(sorted(set(subjects)))
2

How many of each problem

Counting blanks and repeats turns “the data seems a bit messy” into “4 of 300 scores are blank and 2 students appear twice”, which is something you can act on and report.

scores = ["92", "", "88", "", "79"]
print("blank:", scores.count(""), "of", len(scores))

names = ["Ada", "Grace", "Ada"]
print("repeated:", len(names) - len(set(names)))

Key idea: Looking is not cleaning. The next four lessons fix each problem in turn; this one is about knowing they are there before any number leaves your program.

Mini Practice #2: Count the blanks

Try It Yourself

Print how many scores are blank and how many names are repeated.

Press Run to see output

Step 4: When to Use It

Every new file

Look at the distinct values and count blanks and repeats before any summary leaves your program.

print(sorted(set(column)))

When a result surprises you

An unexpected average is more often dirty data than a discovery. Inspect before you explain.

When Not to Use It

Do not start fixing as soon as you see a problem. Count all four kinds first, so you can report what was wrong and decide the order of the fixes.

End-of-Lesson Exercises

Exercise 1: Count the missing scores

Write count_missing(rows) that returns how many rows have an empty string for score.

An empty string is falsy, which is convenient and also a trap: 0 is falsy too. Compare against "" when that is what you mean.

Press Run to try it, then Check my work to mark it.

Exercise 2: A dirt report

Write dirt_report(rows) for rows with name and score keys (both strings). Return a dictionary with three counts: "blank", scores that are empty or only spaces; "not_number", non-blank scores that are not made of digits; and "repeated", how many rows repeat a name already seen.

Keep a set of names seen so far. For each row: if score.strip() == "" it is blank; elif not score.strip().isdigit() it is not a number; and if the name is already in the set it is a repeat.

Press Run to try it, then Check my work to mark it.