pandas
data manipulation
merge
python
data analysis

How to keep index when using pandas merge

ML System Design practice on Codemia

Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.

Practice ML system design

Introduction

pandas.merge usually builds a new RangeIndex unless you explicitly merge on an index or restore the old index afterward. So if you want to keep an existing index, you need to decide whether that index is part of the join key or whether it should simply survive the merge unchanged.

Why the Index Often Disappears

When you merge on ordinary columns, pandas treats the operation like a relational join and constructs a new result frame.

python
1import pandas as pd
2
3left = pd.DataFrame(
4    {"id": [1, 2, 3], "value": ["a", "b", "c"]},
5    index=["r1", "r2", "r3"]
6)
7
8right = pd.DataFrame(
9    {"id": [1, 2, 3], "score": [10, 20, 30]}
10)
11
12merged = left.merge(right, on="id")
13print(merged)
14print(merged.index)

The result gets a fresh default index because the merge was defined on the id column, not on left.index.

That is normal pandas behavior.

If the Index Is Part of the Join, Merge on It

If the index itself is the key you want to preserve, use left_index=True and or right_index=True.

python
1import pandas as pd
2
3left = pd.DataFrame({"value": ["a", "b", "c"]}, index=["k1", "k2", "k3"])
4right = pd.DataFrame({"score": [10, 20, 30]}, index=["k1", "k2", "k3"])
5
6merged = left.merge(right, left_index=True, right_index=True)
7print(merged)
8print(merged.index)

That keeps the shared index as the join key and preserves it in the result.

This is usually the cleanest answer when the index is logically part of the data model.

Preserve the Left Index When Merging on Columns

Sometimes the index is not a join key, but you still want the left frame's index to remain attached. A common pattern is:

  1. reset the index into a temporary column
  2. merge
  3. set the index back
python
1import pandas as pd
2
3left = pd.DataFrame(
4    {"id": [1, 2, 3], "value": ["a", "b", "c"]},
5    index=["r1", "r2", "r3"]
6)
7
8right = pd.DataFrame(
9    {"id": [1, 2, 3], "score": [10, 20, 30]}
10)
11
12merged = (
13    left.reset_index()
14        .merge(right, on="id")
15        .set_index("index")
16)
17
18print(merged)
19print(merged.index)

This is explicit and works well when the left index is just row identity you want to carry through the merge.

You may want to rename the temporary index column to something clearer first:

python
1merged = (
2    left.reset_index(names="row_id")
3        .merge(right, on="id")
4        .set_index("row_id")
5)

That avoids generic column names such as "index".

Use join When the Shape Fits Better

If your goal is "keep the left index and bring in columns from another frame," DataFrame.join is often more natural than merge.

python
1left = pd.DataFrame(
2    {"id": [1, 2, 3], "value": ["a", "b", "c"]},
3    index=["r1", "r2", "r3"]
4)
5
6right = pd.DataFrame(
7    {"score": [10, 20, 30]},
8    index=["r1", "r2", "r3"]
9)
10
11joined = left.join(right)
12print(joined)

join is especially convenient when the index is already the thing you want to align on.

Watch Out for Duplicates

Preserving an index is easy only if the merge semantics make sense. If the right side creates one-to-many matches, the left index can repeat.

python
1right = pd.DataFrame(
2    {"id": [1, 1, 2], "score": [10, 11, 20]}
3)
4
5merged = (
6    left.reset_index(names="row_id")
7        .merge(right, on="id")
8        .set_index("row_id")
9)

Now the index may contain duplicate labels because one left row expanded into several rows. That is not a pandas bug. It reflects the join shape.

Always confirm whether the cardinality of the join still makes your original index meaningful.

Common Pitfalls

  • Expecting merge to preserve the existing index automatically.
  • Forgetting to use left_index=True and right_index=True when the index is the join key.
  • Restoring the index after merge without noticing that the join duplicated rows.
  • Using merge when join would be simpler and more index-friendly.
  • Losing track of the original row identifier by resetting the index without naming the temporary column clearly.

Summary

  • 'pandas.merge usually creates a new default index unless you tell it otherwise.'
  • If the index is the join key, merge on the index directly.
  • If the left index should merely survive, reset it, merge, then set it back.
  • Use join when the operation is really index alignment rather than a column-based relational merge.
  • Check join cardinality before assuming the restored index still has the same semantics.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

ML System Design practice on Codemia

Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.

Practice ML system design

All Rights Reserved.