A join pairs every matching row on the left with every matching row on the right. If a key appears once on the right, each left row gets one match. If it appears three times, each left row is copied three times. That's how a sales table of 120 orders turns into 300 rows after a join, and why totals suddenly double.
Habits that prevent it:
- Count rows before and after every join:
len(df) and len(merged).
- Check the key is unique on the side you expect:
other["key"].duplicated().any().
- Make it unique first: keep the latest row per key (
sort_values, then drop_duplicates(keep="last")), or aggregate to one row per key.
- Join on every column that identifies a row: targets are per region and month, so joining on region alone copies each order six times.