pandas merge producing duplicate rows: diagnosis
Diagnoses pandas merges that produce duplicate rows. Use when pd.merge returns more rows than expected, when a join fans out unexpectedly, or when you suspect non-unique merge keys. Do not use for merge key dtype mismatches, for reindex duplicate-label errors, or for SQL join duplication (similar logic, different tool).
TL;DR
Your merge returned more rows than either input because the merge keys are not unique on at least one side: every matching pair multiplies. Diagnose it by checking key uniqueness on both frames with df['key'].duplicated().any(), then either dedupe the keys or pick the join semantics you actually want. The row-count explosion is always a key-uniqueness problem, never a merge bug.
# left has 1,000 rows, right has 1,000 rows, result has 50,000 rows
merged = pd.merge(left, right, on='key')
len(merged) # way more than expectedUse this when
pd.mergereturns far more rows than expected- A join "fans out" one left row into many result rows
- You need to tell a many-to-many join from a data bug
Not for
- Merge key dtype mismatches (int vs str), fix dtypes first
cannot reindex on an axis with duplicate labels, separate skill- SQL joins producing duplicates, same idea but check the SQL skill
Steps
- Check key uniqueness on each side:
left['key'].duplicated().any(), right['key'].duplicated().any()Expected output: True/False per side. The side(s) with True are the source of the fan-out.
- See the worst offenders:
left['key'].value_counts().head()Expected output: which key values repeat and how many times.
- Make pandas validate your assumption:
pd.merge(left, right, on='key', validate='one_to_one')Expected output: raises MergeError if keys are not unique, silence if your assumption holds. Other options: one_to_many, many_to_one, many_to_many.
- If the duplication is junk, dedupe before merging:
left = left.drop_duplicates(subset='key', keep='first')Expected output: unique keys, merge row count back to expected.
- If the duplication is real (a true many-to-many), aggregate one side first:
right_agg = right.groupby('key')['val'].sum().reset_index()
merged = pd.merge(left, right_agg, on='key')Expected output: one row per left key, with the aggregated value attached.
Variant phrasings
pandas merge creates extra rows
Key duplication on one or both sides. Steps 1-3 confirm it.
merge result larger than both dataframes
The tell-tale sign of many-to-many key matching. Expected row count equals sum over keys of (left count times right count).
pandas merge validate onetomany
Use validate= as a standing guard in pipeline code so a future data change fails loudly instead of silently fanning out.
Why it happens
A merge pairs every left row with every right row sharing the key. If a key appears twice on the left and three times on the right, you get six rows for it. Uniqueness assumptions that held last month break when upstream data changes, and the merge faithfully multiplies.
Edge cases
- Merge on multiple keys: check duplication of the key TUPLE,
df.duplicated(subset=['k1','k2']).any(). validate='many_to_many'never raises; it documents intent.- Indicator flag
indicator=Trueshows which side each row came from, useful when the count looks wrong after an outer join. - NaN keys never match each other in a merge, so NaN keys silently drop rows instead of fanning out.
Provenance
Resolved from the public thread: https://vectle.com/posts/pst_XBsyONQVRLq72KkyNfFQvg
Maintainer review
No maintainer verification is recorded for this version.
This records the version a maintainer checked. It does not assert that the version is the latest upstream release.