Duplicate records are one of the most damaging data defects precisely because they are invisible. A duplicated customer row does not throw an error; it just quietly doubles that customer's revenue in every total. Removing duplicates means finding rows that repeat and keeping only the copy you want, so counts, sums and averages reflect reality. In pandas the two tools are duplicated() to detect and drop_duplicates() to remove, but the real skill is deciding what counts as a duplicate.
This topic pairs closely with inconsistent category labels, because near-duplicates often hide behind small text differences, and it builds on the overview in what is data cleaning.
What "duplicate" actually means
There are two kinds. An exact duplicate is a row identical to another across every column — usually a data-entry or import glitch. A key duplicate is a row that repeats a business key, like the same email or customer_id, even though other columns differ. Which one you care about depends on the grain of the table: what a single row is supposed to represent. If each row should be one unique customer, two rows with the same email are duplicates even if their spend differs. If each row is one purchase, the same customer appearing twice is perfectly correct.
Getting this right is the whole game. Blindly deleting repeated customers when rows are meant to be purchases destroys real data.
Detecting duplicates
Start by looking, never by deleting. Here is an illustrative messy sample.
import pandas as pd
df = pd.DataFrame({
"customer_id": [1, 2, 2, 3, 3, 4],
"email": ["a@x.com", "b@x.com", "b@x.com", "c@x.com", "c@x.com", "d@x.com"],
"order": ["A100", "A101", "A101", "A102", "A103", "A104"],
"amount": [1200, 980, 980, 550, 600, 760],
})
print("exact dup rows:", df.duplicated().sum())
print(df[df.duplicated(keep=False)]) # show every row involved
Expected output:
exact dup rows: 1
customer_id email order amount
1 2 b@x.com A101 980
2 2 b@x.com A101 980
duplicated() flags the second identical row for customer 2. Notice customer 3 appears twice too, but those rows are not exact duplicates — different orders and amounts — so they are not flagged. Whether they are a problem depends entirely on the table's grain.
Removing exact duplicates
For true identical repeats, drop_duplicates() keeps one copy:
clean = df.drop_duplicates()
print(clean)
customer_id email order amount
0 1 a@x.com A100 1200
1 2 b@x.com A101 980
3 3 c@x.com A102 550
4 3 c@x.com A103 600
5 4 d@x.com A104 760
The duplicate A101 row is gone; customer 3's two distinct orders correctly remain. drop_duplicates() defaults to keep='first', retaining the earliest copy. Use keep='last' to keep the most recent, or keep=False to drop every copy of anything duplicated (useful when you want to isolate and inspect them rather than trust either version).
Deduplicating by a business key
When rows should be unique by an id or email but other fields drift, dedupe on a subset:
# keep only one row per customer_id, preferring the last (most recent) record
one_per_customer = df.drop_duplicates(subset=["customer_id"], keep="last")
print(one_per_customer[["customer_id", "email", "order", "amount"]])
customer_id email order amount
0 1 a@x.com A100 1200
2 2 b@x.com A101 980
4 3 c@x.com A103 600
5 4 d@x.com A104 760
Now there is exactly one row per customer. keep='last' kept customer 3's second order — the choice of first versus last should match which record you trust, for example the most recent update.
A frequent real-world need is to keep the most complete or most recent record per key rather than an arbitrary first or last. The pattern is to sort first, then dedupe: sort by an update timestamp descending, then drop_duplicates(subset=[key], keep='first') retains the newest row per key. Sorting before deduping turns keep from a blind choice into a deliberate rule, and is how analysts collapse a change-log of updates down to one current record per entity.
How analysts use it
The professional routine: first establish the grain ("one row = one what?"), then check exact duplicates with duplicated().sum(), then check key duplicates with duplicated(subset=[key]). Inspect the flagged rows before deleting, because a "duplicate" is sometimes two legitimate events or two conflicting records that need reconciling, not deleting. When deduping by key, decide deliberately whether the first or last record wins. Finally, re-check your headline totals before and after — a big drop in a sum after dedup is a signal that duplicates were meaningfully inflating your numbers.
Common mistakes
- Deleting without inspecting. Running
drop_duplicates()blind can remove legitimate rows. Always viewdf[df.duplicated(keep=False)]first. - Confusing grain. Treating repeated customers as duplicates when each row is meant to be a purchase deletes real transactions. Define the grain before deduping.
- Ignoring near-duplicates. " b@x.com " with a trailing space, or "B@X.com" in different case, will not match as duplicates until the text is standardized. Clean text first (see inconsistent category labels).
- Defaulting to keep='first' without thinking. If the latest record is the corrected one, keeping the first retains stale data. Match
keepto which copy you trust.
In interviews
Expect "How would you find and remove duplicate rows?" and follow-ups about deduping by key columns. Strong answers name duplicated() and drop_duplicates(), explain the subset and keep arguments, and — most importantly — raise the grain question: you cannot decide what a duplicate is without knowing what one row represents. Mentioning that text inconsistencies hide duplicates, and that you inspect before deleting, shows maturity beyond memorized syntax.
Where this fits in your learning path
Removing duplicates is a core early skill in the data cleaning cluster, right alongside missing-value handling. It follows naturally from what is data cleaning and connects to inconsistent category labels, since standardizing text is what makes hidden duplicates visible. Reliable deduplication is a fundamental part of the data analyst roadmap.
Frequently Asked Questions
How do I find duplicate rows in pandas?
What does the keep argument do in drop_duplicates?
How do I remove duplicates based on only some columns?
Why are duplicates dangerous in analysis?
Should I always remove duplicates?
Want to Build Your Career in Data Analytics with AI?
Join CodeBegun and train with working industry engineers — Explore the Data Analytics program

