merge и concat: соединение таблиц с контролем кардинальности
Содержание курса
В прошлом уроке transform помогал добавлять к каждой строке групповой показатель — сумму или среднее — не выходя за пределы одного DataFrame. Но если нужные данные хранятся в двух разных таблицах, transform не поможет: нужна операция явного соединения. Именно её разберём сейчас.
pd.merge: параметры on и how — механика четырёх типов соединения
pd.merge — основная функция pandas для соединения двух DataFrame по общему ключевому столбцу. Минимальный вызов выглядит так:
import pandas as pd
orders = pd.DataFrame({'order_id': [1, 2, 3], 'amount': [100, 200, 300]})
clients = pd.DataFrame({'order_id': [1, 2, 4], 'client': ['Аня', 'Боря', 'Вера']})
result = pd.merge(orders, clients, on='order_id', how='inner')
print(result)
# order_id amount client
# 0 1 100 Аня
# 1 2 200 Боря
Параметр on указывает имя столбца, по которому идёт сравнение. Он должен присутствовать в обоих DataFrame. Параметр how задаёт правило отбора строк в результат — и именно здесь поведение четырёх режимов принципиально расходится.
inner — строгое пересечение. В результат попадают только те строки, у которых значение ключа есть в обеих таблицах. В примере выше order_id=3 нет в clients, order_id=4 нет в orders — обе строки отброшены.
left — все строки левого DataFrame сохраняются. Если для какого-то order_id из orders нет совпадения в clients, строка всё равно попадает в результат.
left = pd.merge(orders, clients, on='order_id', how='left')
print(left)
# order_id amount client
# 0 1 100 Аня
# 1 2 200 Боря
# 2 3 300 NaN
print(left.shape) # (3, 3)
order_id=3 присутствует, но client для него — NaN, потому что в правой таблице такой записи нет.
right — симметрично left: все строки правого DataFrame (clients) сохраняются, строки левого (orders) добавляются там, где есть совпадение.
right = pd.merge(orders, clients, on='order_id', how='right')
print(right)
# order_id amount client
# 0 1 100.0 Аня
# 1 2 200.0 Боря
# 2 4 NaN Вера
print(right.shape) # (3, 3)
order_id=4 есть только в clients, поэтому amount для него — NaN.
outer — объединение всех строк из обоих DataFrame. Строки без пары получают NaN в столбцах противоположной таблицы.
outer = pd.merge(orders, clients, on='order_id', how='outer')
print(outer)
# order_id amount client
# 0 1 100.0 Аня
# 1 2 200.0 Боря
# 2 3 300.0 NaN
# 3 4 NaN Вера
print(outer.shape) # (4, 3)
Четыре строки: две совпавших, одна только из orders, одна только из clients.
Параметр on принимает не только строку, но и список столбцов, если ключ составной: on=['user_id', 'date']. Главное требование — все перечисленные столбцы должны существовать в обоих DataFrame с одинаковыми именами.
Выбор how — это не технический, а смысловой вопрос. Он зависит от того, какие строки нельзя потерять: если приоритет у левой таблицы (основная сущность) — left; если нужно полное покрытие обеих — outer; если важны только подтверждённые совпадения — inner.
