merge в Pandas — полный гайд по объединению таблиц

Коротко

pd.merge() — аналог SQL JOIN в Python. Берёт два DataFrame и соединяет их по общему ключу. Если вы знаете JOIN в SQL, разобраться с merge — дело пяти минут. На собеседованиях аналитика merge спрашивают в live-coding секции: дают два датафрейма и просят объединить, посчитать метрику, найти пропуски.

Базовый синтаксис

import pandas as pd

users = pd.DataFrame({
    'user_id': [1, 2, 3, 4],
    'name': ['Анна', 'Борис', 'Вика', 'Глеб']
})

orders = pd.DataFrame({
    'user_id': [1, 1, 3, 5],
    'amount': [500, 300, 1200, 800]
})

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

По умолчанию merge делает inner join — оставляет только строки, где ключ есть в обеих таблицах. В примере выше Борис и Глеб (нет заказов) и user_id=5 (нет в users) выпадут.

Параметр how — тип соединения

Параметр how определяет, какие строки попадут в результат. Логика та же, что и в SQL JOIN:

how Аналог в SQL Что делает
'inner' INNER JOIN Только совпадения (по умолчанию)
'left' LEFT JOIN Все строки из левого DataFrame
'right' RIGHT JOIN Все строки из правого DataFrame
'outer' FULL OUTER JOIN Все строки из обоих DataFrame
# Все пользователи + их заказы (у кого нет — NaN)
result = pd.merge(users, orders, on='user_id', how='left')

# Все комбинации — никто не теряется
result = pd.merge(users, orders, on='user_id', how='outer')

Самая частая ошибка на собесе: забыть указать how='left' и потерять строки без совпадений. По умолчанию merge делает inner — молча отбрасывает несопоставленные записи.

on, left_on, right_on — ключи соединения

Если столбец-ключ называется одинаково в обоих DataFrame — используйте on:

pd.merge(users, orders, on='user_id')

Если названия различаются — left_on и right_on:

events = pd.DataFrame({
    'uid': [1, 2, 3],
    'event': ['login', 'purchase', 'login']
})

pd.merge(users, events, left_on='user_id', right_on='uid')

Соединение по нескольким ключам — передайте список:

pd.merge(df1, df2, on=['user_id', 'date'])

suffixes — конфликты имён столбцов

Если в обоих DataFrame есть столбец с одинаковым названием (не ключ), merge автоматически добавит суффиксы _x и _y. Можно задать свои:

users_with_city = pd.DataFrame({
    'user_id': [1, 2], 'name': ['Анна', 'Борис'], 'source': ['organic', 'paid']
})
orders_with_source = pd.DataFrame({
    'user_id': [1, 2], 'amount': [500, 300], 'source': ['web', 'app']
})

result = pd.merge(users_with_city, orders_with_source,
                  on='user_id',
                  suffixes=('_user', '_order'))
# Столбцы: user_id, name, source_user, amount, source_order

indicator — откуда строка

Параметр indicator=True добавляет столбец _merge, который показывает, из какого DataFrame пришла строка:

result = pd.merge(users, orders, on='user_id', how='outer', indicator=True)
print(result['_merge'].value_counts())
# both          — совпадение в обоих
# left_only     — только в левом (users)
# right_only    — только в правом (orders)

Удобно для дебага: быстро понять, кто не смерджился и почему.

Дубликаты и many-to-many

Если ключ не уникален в обоих DataFrame, merge делает декартово произведение по совпавшим ключам. Это главный источник «неожиданно разросшегося» DataFrame:

df1 = pd.DataFrame({'key': ['a', 'a'], 'val1': [1, 2]})
df2 = pd.DataFrame({'key': ['a', 'a'], 'val2': [10, 20]})

result = pd.merge(df1, df2, on='key')
# 4 строки вместо 2! Каждая строка df1 соединяется с каждой строкой df2

Защита: перед merge проверяйте уникальность ключа через df['key'].duplicated().sum(). Или используйте параметр validate:

pd.merge(df1, df2, on='key', validate='one_to_many')
# Бросит MergeError, если ключ не уникален в левом DataFrame

Варианты validate: 'one_to_one', 'one_to_many', 'many_to_one', 'many_to_many'.

merge vs join vs concat

merge join concat
Что делает Соединение по столбцам (аналог SQL JOIN) Соединение по индексу Склейка по строкам или столбцам
Когда использовать Объединение по ключу (user_id, date) Оба DataFrame уже проиндексированы по ключу Объединение однотипных таблиц (январь + февраль)
Синтаксис pd.merge(df1, df2, on='key') df1.join(df2, on='key') pd.concat([df1, df2])

В 90% случаев на собеседовании нужен именно merge. concat полезен, когда нужно склеить одинаковые по структуре таблицы (например, данные за разные месяцы). join — редко используется, merge покрывает те же задачи.

Практический пример: воронка пользователей

Частая задача на собесе: есть пользователи и события, нужно посчитать конверсию.

users = pd.DataFrame({
    'user_id': [1, 2, 3, 4, 5],
    'reg_date': pd.to_datetime(['2025-01-01', '2025-01-02', '2025-01-03',
                                 '2025-01-04', '2025-01-05']),
    'source': ['organic', 'paid', 'organic', 'paid', 'organic']
})

purchases = pd.DataFrame({
    'user_id': [1, 3],
    'purchase_date': pd.to_datetime(['2025-01-05', '2025-01-10']),
    'revenue': [990, 1490]
})

# LEFT merge — сохраняем всех пользователей
funnel = pd.merge(users, purchases, on='user_id', how='left')

# Конверсия в покупку
conversion = funnel['revenue'].notna().mean()
print(f'Конверсия: {conversion:.0%}')  # 40%

# Конверсия по источнику
funnel.groupby('source')['revenue'].apply(lambda x: x.notna().mean())

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

  1. Забыли how='left' — потеряли строки без совпадений, даже не заметили.
  2. Дубликаты в ключе — DataFrame размножился в 10 раз, метрики сломались.
  3. Разные типы ключа — в одном DataFrame ключ int, в другом str. Merge вернёт пустой результат без ошибки. Проверяйте df['key'].dtype.
  4. Несколько merge подряд без проверки — каждый merge может множить строки. Проверяйте shape после каждого.

Вопросы с собеседований

Чем merge отличается от join в pandas? merge соединяет по столбцам (как SQL JOIN), join — по индексу. merge гибче: можно указать произвольные столбцы через on, left_on, right_on. На практике merge используют чаще.

Что произойдёт, если ключ не уникален в обоих DataFrame? merge сделает декартово произведение по совпавшим ключам. Если в левом 3 строки с key='a' и в правом 2 строки с key='a', результат — 6 строк. Это many-to-many join. Чтобы защититься, используйте validate='one_to_many'.

Как проверить, какие строки не смерджились? Использовать indicator=True. Merge добавит столбец _merge со значениями both, left_only, right_only. Строки left_only — те, что не нашли пару в правом DataFrame.

Какой how по умолчанию в merge? inner — только совпадения. Это отличается от SQL, где тип JOIN указывается явно. Частая ошибка — забыть параметр how и молча потерять строки.

В чём разница merge и concat? merge соединяет по ключу «горизонтально» (добавляет столбцы). concat склеивает «вертикально» (добавляет строки). merge — это JOIN, concat — это UNION ALL.


Потренируйтесь решать задачи — откройте тренажёр с 1500+ вопросами для подготовки к собеседованиям аналитиков.

FAQ

Можно ли мерджить больше двух таблиц? Да, но последовательно. Каждый вызов merge принимает два DataFrame. Для трёх таблиц — два merge подряд. Используйте functools.reduce, если таблиц много: reduce(lambda l, r: pd.merge(l, r, on='key'), [df1, df2, df3]).

Что быстрее — merge в pandas или JOIN в SQL? SQL. Базы данных оптимизированы для соединений: индексы, hash join, merge join. Pandas работает в оперативной памяти без индексов (если не создали явно). На больших данных (миллионы строк) разница ощутима.

Как сделать cross join в pandas? pd.merge(df1, df2, how='cross') — доступно с pandas 1.2+. Возвращает декартово произведение всех строк.


Потренироваться в merge и других операциях pandas можно в Python-тренажёре. Там задачи в формате собеседования — с DataFrame, groupby и объединением таблиц. Больше примеров вопросов — на странице примеры вопросов, шпаргалка по всем операциям — в pandas шпаргалке.