Как объединить DataFrame в pandas

Карьерник — квиз-тренажёр в Telegram с 1500+ вопросами для собесов аналитика. SQL, Python, A/B, метрики. Бесплатно.

Три способа объединения

  • pd.merge() — по ключу (аналог SQL JOIN)
  • pd.concat() — по оси (вертикально или горизонтально)
  • df.join() — по индексу (упрощённый merge)

1. merge — самый частый

import pandas as pd

users = pd.DataFrame({
    'user_id': [1, 2, 3],
    'name': ['Alice', 'Bob', 'Carol']
})

orders = pd.DataFrame({
    'order_id': [101, 102, 103],
    'user_id': [1, 1, 2],
    'total': [100, 200, 50]
})

# INNER JOIN
result = pd.merge(users, orders, on='user_id')

# LEFT JOIN
result = pd.merge(users, orders, on='user_id', how='left')

# OUTER JOIN
result = pd.merge(users, orders, on='user_id', how='outer')

Типы how

  • 'inner' — только совпадения (default)
  • 'left' — все из левого, совпавшие из правого
  • 'right' — все из правого
  • 'outer' — все из обоих
  • 'cross' — декартово произведение (pandas 1.2+)

2. merge по разным колонкам

pd.merge(
    left=users,
    right=orders,
    left_on='id',           # колонка в users
    right_on='user_id'      # колонка в orders
)

3. merge по нескольким ключам

pd.merge(df1, df2, on=['country', 'city'])

4. Переименование колонок при merge

Если есть конфликтующие колонки:

pd.merge(df1, df2, on='user_id', suffixes=('_a', '_b'))
# name_a и name_b вместо name_x и name_y (default)

5. concat — сложить под или сбоку

# вертикально (одна под другой)
pd.concat([df1, df2])

# горизонтально
pd.concat([df1, df2], axis=1)

# сбросить индекс
pd.concat([df1, df2]).reset_index(drop=True)

concat аналогичен SQL UNION ALL.

6. concat с разными колонками

Если в df1 колонок нет в df2:

pd.concat([df1, df2])
# недостающие заполняются NaN

# только общие колонки
pd.concat([df1, df2], join='inner')

7. join — по индексу

# merge смотрит на колонки, join — на индекс
result = df1.join(df2)  # по индексу
result = df1.join(df2, how='left')

Удобно, когда индекс — это ключ (например, user_id как индекс).

8. merge vs concat vs join

Задача Функция
JOIN двух таблиц по ключу pd.merge
UNION ALL (стакать под) pd.concat(axis=0)
Сбоку приклеить по индексу pd.concat(axis=1) или df.join
JOIN по индексу df.join

9. Проверка качества merge

# indicator=True добавляет колонку _merge
result = pd.merge(df1, df2, on='id', how='outer', indicator=True)

# смотрим, где совпали
result['_merge'].value_counts()
# both          100
# left_only      5
# right_only     3

Используйте, чтобы проверить, корректно ли работает merge.

10. Many-to-many — осторожно

Если в обоих DataFrame ключ неуникален, merge даст cartesian (каждая со каждой в группе ключа).

# users: 1 строка на юзера
# orders: N строк на юзера
merge ok: users × orders → N строк

# users: 5 строк на юзера (почему-то)
# orders: 3 строки на юзера
# merge: 15 строк на юзера — вероятно, ошибка

Проверяйте через validate:

pd.merge(df1, df2, on='user_id', validate='one_to_many')
# one_to_one, one_to_many, many_to_one, many_to_many

11. Объединить много DataFrame

from functools import reduce

dfs = [df1, df2, df3, df4]
result = reduce(lambda a, b: pd.merge(a, b, on='user_id'), dfs)

Частые ошибки

1. Дубликаты после merge

Часто из-за неуникальных ключей. Проверьте через df.duplicated('key').sum().

2. Потерянные строки

INNER JOIN + один ключ отсутствует в одной таблице → строка пропадает. Используйте LEFT.

3. Забыть suffixes

# pandas сам добавит _x и _y
pd.merge(df1, df2, on='user_id')
# df1.name → name_x
# df2.name → name_y

Понятнее — явные suffixes.

4. concat с разным индексом

df1 = pd.DataFrame(..., index=[0, 1, 2])
df2 = pd.DataFrame(..., index=[0, 1, 2])

pd.concat([df1, df2])
# индекс: [0, 1, 2, 0, 1, 2] — дубли
# нужно reset_index(drop=True)

Связанные темы

FAQ

merge vs join?

merge — по колонкам. join — по индексу. merge универсальнее.

concat или merge?

concat — стакать (UNION). merge — JOIN по ключу.

Как сохранить порядок?

merge нарушает порядок. Для сохранения — добавить sort-колонку и сортировать после.

Cartesian случился, что делать?

Проверить уникальность ключа в обеих таблицах. Добавить validate='one_to_many'.


Тренируйте pandas — откройте тренажёр с 1500+ вопросами для собесов.