pandas·Lesson 10·9 min·0/4 exercises

Duplicates

“Duplicate” is a decision you make, and subset= is where you make it.

.duplicated().drop_duplicates()keep=subset=.value_counts()is_unique

Watch it happen

Play it through, or step back and forth yourself.

orders
date
city
item
cups
revenue
rating
5
2026-03-04
Delhi
elaichi
110
2530.0
4.1
6
2026-03-04
Delhi
ginger
85
1700.0
4.0
7
2026-03-05
Pune
ginger
70
1400.0
NaN
8
2026-03-05
Delhi
masala
130
2600.0
4.6
9
2026-03-05
Delhi
masala
130
2600.0
4.6

Rows 8 and 9 are byte-for-byte the same — same date, city, item, cups, revenue and rating. It's the kind of thing an export run twice leaves behind, and it will quietly inflate every total you compute.

The idea

Rows 8 and 9 of orders are identical in every column. An export run twice, a form submitted twice, a join gone wrong — they arrive constantly, and they silently inflate every total you compute.

Finding them

orders.duplicated()          # True for rows already seen
orders.duplicated().sum()    # 1 — the number of EXTRA copies

The first occurrence is False and the repeat is True. That's worth holding on to: the count is the number of surplus rows, not the number of rows involved. Two rows that duplicate each other give a count of 1.

keep="first"   # default — mark later copies
keep="last"    # mark earlier copies instead
keep=False     # mark EVERY row that has a twin

keep=False is the one to use when you're looking rather than deleting, because it shows you both sides of each collision:

orders[orders.duplicated(keep=False)].sort_values(["date", "city"])

Removing them

orders.drop_duplicates()                    # 12 of 13 rows — keeps the first of each
orders.drop_duplicates(keep="last")         # keeps the last instead
orders.drop_duplicates(ignore_index=True)   # renumber 0..n afterwards

Like filtering, this keeps the original index labels — row 9 is simply gone and the rest don't renumber. Pass ignore_index=True if you'd rather they did.

subset — the part that matters

By default a duplicate means "every column identical". That's rarely the question you actually have. More often you mean "this key should only appear once":

orders.duplicated(subset=["date", "city"])     # 2 — rows 6 and 9
orders.drop_duplicates(subset=["date", "city"], keep="last")

Now two rows that differ in cups still count as duplicates, because the pair (date, city) is what you've declared should be unique.

Whether they are duplicates is a judgement about your data, not a fact pandas can work out. Two orders from the same stall on the same day might be a data error, or might be a morning and an afternoon delivery. subset= is where you record which.

Look before you delete

drop_duplicates() is one call and it's irreversible. Inspect first, every time:

dupes = orders[orders.duplicated(subset=["date", "city"], keep=False)]
dupes.sort_values(["date", "city"])   # why do these collide?

Very often the answer is that they aren't duplicates at all — they're two real events and the key you picked was too coarse. Deleting them would have quietly lost data.

Related checks

orders["city"].value_counts()      # how often each value appears
orders["city"].nunique()           # 3 distinct cities
orders.index.is_unique             # the index can have duplicates too
orders.value_counts().head()       # which whole rows repeat

A non-unique index causes surprising behaviour later — .loc[3] quietly returns several rows instead of one — so it's worth checking after any concat.

See it run

The lesson's code, ready to run and to fiddle with.

Putting the kettle on…

Starting up…

Worked example

not graded

Already written and ready to go — press Run to see what it does, then change a number, a column name, anything, and run it again.

trysubset=["date", "city", "item"] and see whether the count changes.

Press Run — the output appears here.

Your turn

4 exercises. Write the code yourself, then press Check — a nudge and the answer are there if you want them.

How many extra copies are there in orders? Return the count.

your answer

Return every row involved in a duplication — both the original and the copy, not just the repeat.

your answer

Return orders with the duplicate removed, keeping the first of each.

your answer

How many rows repeat the pair date + city? Return the count.

your answer