concat vs merge в Pandas — когда что использовать
Коротко
concat склеивает DataFrames друг под другом (или рядом). merge соединяет по общему ключу — аналог JOIN в SQL. Разница: concat не требует общего столбца, merge — требует. Правило: если данные одинаковой структуры и нужно объединить в один файл — concat. Если нужно добавить информацию из другой таблицы по ключу — merge. На собеседованиях аналитиков это одна из ключевых тем по pandas.
concat — склейка DataFrames
По вертикали (друг под другом)
import pandas as pd
df_jan = pd.DataFrame({
'user_id': [1, 2, 3],
'revenue': [5000, 3200, 8100]
})
df_feb = pd.DataFrame({
'user_id': [2, 3, 4],
'revenue': [4100, 7500, 2800]
})
df_all = pd.concat([df_jan, df_feb])
# user_id revenue
# 0 1 5000
# 1 2 3200
# 2 3 8100
# 0 2 4100
# 1 3 7500
# 2 4 2800Индексы дублируются. Добавьте ignore_index=True для сброса:
df_all = pd.concat([df_jan, df_feb], ignore_index=True)
# user_id revenue
# 0 1 5000
# 1 2 3200
# 2 3 8100
# 3 2 4100
# 4 3 7500
# 5 4 2800По горизонтали (рядом)
df_names = pd.DataFrame({
'user_id': [1, 2, 3],
'name': ['Иван', 'Анна', 'Пётр']
})
df_scores = pd.DataFrame({
'score': [85, 92, 78]
})
df = pd.concat([df_names, df_scores], axis=1)
# user_id name score
# 0 1 Иван 85
# 1 2 Анна 92
# 2 3 Пётр 78axis=0 (по умолчанию) — вертикально. axis=1 — горизонтально. При горизонтальной склейке строки сопоставляются по индексу.
С разными столбцами
df1 = pd.DataFrame({'user_id': [1], 'revenue': [5000]})
df2 = pd.DataFrame({'user_id': [2], 'revenue': [3200], 'city': ['Москва']})
pd.concat([df1, df2], ignore_index=True)
# user_id revenue city
# 0 1 5000 NaN
# 1 2 3200 МоскваСтолбцы, отсутствующие в одном из DataFrame, заполняются NaN. Это join='outer' (по умолчанию). Для пересечения столбцов: join='inner'.
merge — соединение по ключу
Базовый merge
orders = pd.DataFrame({
'order_id': [1, 2, 3],
'user_id': [101, 102, 101],
'amount': [5000, 3200, 8100]
})
users = pd.DataFrame({
'user_id': [101, 102, 103],
'name': ['Иван', 'Анна', 'Пётр']
})
result = orders.merge(users, on='user_id')
# order_id user_id amount name
# 0 1 101 5000 Иван
# 1 2 102 3200 Анна
# 2 3 101 8100 ИванПо умолчанию — inner merge: только строки с совпадающим ключом. Пётр (user_id=103) не попал — у него нет заказов.
Типы merge (аналоги SQL JOIN)
# Inner — только совпадения
orders.merge(users, on='user_id', how='inner')
# Left — все из левого + совпадения из правого
orders.merge(users, on='user_id', how='left')
# Right — все из правого + совпадения из левого
orders.merge(users, on='user_id', how='right')
# Outer — все из обоих
orders.merge(users, on='user_id', how='outer')| Pandas merge | SQL JOIN | Результат |
|---|---|---|
how='inner' |
INNER JOIN | Только совпадения |
how='left' |
LEFT JOIN | Все из левого |
how='right' |
RIGHT JOIN | Все из правого |
how='outer' |
FULL OUTER JOIN | Все из обоих |
Подробнее — в гайде по merge.
Разные названия ключей
orders = pd.DataFrame({'order_id': [1], 'customer_id': [101], 'amount': [5000]})
users = pd.DataFrame({'user_id': [101], 'name': ['Иван']})
orders.merge(users, left_on='customer_id', right_on='user_id')left_on и right_on — если столбцы-ключи называются по-разному.
Суффиксы при совпадении имён
df1 = pd.DataFrame({'id': [1], 'value': [100]})
df2 = pd.DataFrame({'id': [1], 'value': [200]})
df1.merge(df2, on='id', suffixes=('_left', '_right'))
# id value_left value_right
# 0 1 100 200Сравнение: concat vs merge
| Критерий | concat | merge |
|---|---|---|
| Что делает | Склеивает DataFrames | Соединяет по ключу |
| Нужен общий ключ | Нет | Да |
| Аналог в SQL | UNION ALL | JOIN |
| Направление | Вертикально или горизонтально | Горизонтально |
| Дубликаты | Не убирает | Может размножить строки |
| Типичный кейс | Объединить файлы за разные месяцы | Добавить данные из справочника |
Когда concat
- Одинаковая структура, разные данные:
январь + февраль + март - Объединить результаты нескольких запросов
- Добавить вычисленные столбцы рядом (
axis=1)
Когда merge
- Добавить имена пользователей к заказам
- Присоединить справочник (города, категории)
- Любая задача, где в SQL написали бы JOIN
Практические примеры
Объединить CSV за несколько месяцев
import glob
files = glob.glob('data/orders_*.csv')
dfs = [pd.read_csv(f) for f in files]
df = pd.concat(dfs, ignore_index=True)Обогатить заказы данными о пользователях
orders = pd.read_csv('orders.csv')
users = pd.read_csv('users.csv')
enriched = orders.merge(users, on='user_id', how='left')how='left' — все заказы сохраняются, даже если пользователь не найден (NaN в столбцах из users).
Найти пользователей без заказов
merged = users.merge(orders, on='user_id', how='left', indicator=True)
no_orders = merged[merged['_merge'] == 'left_only']indicator=True добавляет столбец _merge со значениями: both, left_only, right_only. Аналог антиджойна в SQL.
Типичные ошибки
concat вместо merge. Склейка по вертикали не соединяет по ключу — просто кладёт строки друг под друга. Если нужен JOIN — используйте merge.
Дубликаты после merge. Если ключ не уникален в обоих DataFrame, merge создаст декартово произведение для совпадающих ключей. Проверяйте: df.duplicated(subset=['key']).sum().
Потеря строк при inner merge. По умолчанию merge делает inner join — строки без совпадения отбрасываются. Для сохранения всех строк из основного DataFrame — how='left'.
Горизонтальный concat без совпадающих индексов. pd.concat([df1, df2], axis=1) сопоставляет по индексу. Если индексы разные — получите NaN. Используйте merge вместо concat для соединения по ключу.
Вопросы с собеседований
-- Чем отличается concat от merge? -- concat склеивает DataFrames (вертикально или горизонтально) без логики соединения по ключу. merge соединяет по общему столбцу — аналог SQL JOIN. concat ≈ UNION, merge ≈ JOIN.
-- Как объединить два DataFrame по ключу?
-- df1.merge(df2, on='key') для inner join. how='left' / 'right' / 'outer' для других типов. Если ключи называются по-разному: left_on и right_on.
-- Как найти строки, которые есть в одном DataFrame, но нет в другом?
-- df1.merge(df2, on='key', how='left', indicator=True). Фильтрация по _merge == 'left_only'. Альтернатива: df1[~df1['key'].isin(df2['key'])].
-- Когда merge размножает строки? -- Когда ключ не уникален в обоих DataFrame. Например, у пользователя 3 заказа, а в справочнике 2 строки с его city — merge создаст 6 строк. Это аналог CROSS JOIN для совпадающих ключей.
Потренируйтесь решать задачи — откройте тренажёр с 1500+ вопросами для подготовки к собеседованиям аналитиков.
FAQ
concat vs append — в чём разница?
append удалён в pandas 2.0. Используйте pd.concat([df1, df2]) вместо df1.append(df2). Функционально — одно и то же.
merge vs join — в чём разница?
merge — функция/метод для соединения по столбцам. join — метод для соединения по индексу. На практике merge универсальнее и используется чаще.
Как ускорить merge на больших данных?
Убедитесь, что ключевой столбец имеет правильный тип (int, не object). Отсортируйте оба DataFrame по ключу перед merge. Для очень больших данных — рассмотрите SQL или Dask.
Как тренироваться
concat и merge — must-have для аналитика pandas. Задачи на соединение данных — в тренажёре Карьерник. Больше вопросов — в разделе с примерами.