How to Remove Duplicate Rows in Pandas
pandas' drop_duplicates() handles whole-row deduplication out of the box, but the two parameters that make it flexible - subset and keep - are worth understanding properly before you run it on real data.
Quick answer
df.drop_duplicates() removes rows that are exact duplicates across every column, keeping the first occurrence by default. Use subset=['column'] to dedupe based on only specific columns, and keep='last' or keep=False to change which duplicate (if any) survives. Inspect duplicates first with df[df.duplicated(keep=False)] before deleting anything.
Need this for a plain list instead of a DataFrame?
See the full reference for Python, JavaScript, SQL, Google Sheets, and more.
The default: whole-row deduplication
import pandas as pd
df = pd.DataFrame({
'name': ['Alice', 'Bob', 'Alice'],
'email': ['alice@x.com', 'bob@x.com', 'alice@x.com'],
})
df_unique = df.drop_duplicates()
print(df_unique)
# Only the first Alice row remains - both columns matched exactly Without a subset, drop_duplicates() considers every column - two rows only count as duplicates if all of their values match exactly. keep='first' is the default, so the first occurrence of each duplicate group survives.
Deduplicating on specific columns: subset
df_unique = df.drop_duplicates(subset=['email'])
Passing subset narrows the comparison to just the listed columns - two rows with the same email but a different name are still treated as duplicates and one is dropped, since only email is being compared.
Choosing which row survives: keep
df.drop_duplicates(subset=['email'], keep='last') # keep the last occurrence df.drop_duplicates(subset=['email'], keep=False) # keep NEITHER - drop all involved
keep='last' is handy when your data is chronologically ordered and you want the most recent record per key. keep=False is different from the other two - instead of keeping one row per duplicate group, it removes every row that has any duplicate at all, leaving only genuinely unique rows behind.
Inspecting duplicates before deleting
dupes = df[df.duplicated(subset=['email'], keep=False)] print(dupes) # every row involved in a duplicate group, for review
duplicated() returns a boolean mask instead of dropping anything, using the same subset/keep logic as drop_duplicates(). Filtering the DataFrame with this mask first lets you see exactly what would be removed before committing to the deletion.
Ignoring case or whitespace when comparing
df['email_norm'] = df['email'].str.strip().str.lower() df_unique = df.drop_duplicates(subset=['email_norm']).drop(columns=['email_norm'])
drop_duplicates() compares exact string values, so "Alice@X.com" and " alice@x.com " would not be treated as duplicates without normalizing first. Building a normalized helper column, deduping on that, then dropping the helper column keeps the original casing and whitespace in your final output.
Counting occurrences instead of removing them
print(df['email'].value_counts())
Sometimes you want to understand the duplication before acting on it - value_counts() returns how many times each distinct value appears, sorted from most to least frequent, which is useful for spotting which values are duplicated the most before deciding on a subset/keep strategy.
Just have a plain list, not a DataFrame? Paste it here.
Open Remove Duplicate Lines →Working with a plain Python list instead of a DataFrame?
See the plain-list Python guide - dict.fromkeys(), sets, and dicts by key.
Frequently Asked Questions
What is the standard way to remove duplicate rows in pandas?
df.drop_duplicates() removes rows that are exact duplicates across every column, keeping the first occurrence of each by default. It returns a new DataFrame rather than modifying the original in place unless you pass inplace=True.How do I remove duplicates based on only some columns?
subset parameter: df.drop_duplicates(subset=['email']) considers two rows duplicates if they share the same email, regardless of whether other columns differ.How do I control which duplicate row is kept?
keep parameter controls this: keep='first' (the default) keeps the first occurrence, keep='last' keeps the last, and keep=False drops every row that has any duplicate at all, keeping none of them.How do I see which rows are duplicates before deleting them?
df.duplicated() returns a boolean Series marking which rows are duplicates (by the same subset/keep rules as drop_duplicates), so df[df.duplicated(keep=False)] shows you every row involved in a duplicate group for review first.How do I deduplicate ignoring case or whitespace differences?
df['email_norm'] = df['email'].str.strip().str.lower(), then df.drop_duplicates(subset=['email_norm']). Drop the helper column afterward if you don't need it.How do I see how many times each value appears, not just remove duplicates?
df['column'].value_counts() returns a count of each distinct value, sorted from most to least frequent by default - useful when you want to understand the duplication pattern rather than just clean it up.