Условие
Есть orders(order_id, user_id, amount) и users(user_id, segment). Какие будут разницы между inner, left, right, outer join? Как понять, что merge неожиданно «размножил» строки?
Решение
Типы join
how |
Размер | Когда |
|---|---|---|
inner |
<= min(len) |
нужны только совпавшие |
left |
>= len(orders) |
сохранить все заказы, добавить сегмент |
right |
>= len(users) |
сохранить всех юзеров |
outer |
>= max(len) |
full outer, диагностика расхождений |
Защита от «размножения»
res = orders.merge(
users,
on='user_id',
how='left',
validate='m:1', # many orders to one user
indicator=True, # колонка _merge: 'left_only' / 'both' / 'right_only'
)
# Сколько заказов не нашли пользователя:
res['_merge'].value_counts()validate='m:1' упадёт с MergeError, если в users нашлись дубли по user_id.
Диагностика «зачем стало больше строк»
before = len(orders)
after = len(res)
print(after - before, 'extra rows')
print(users['user_id'].duplicated().sum(), 'duplicate users')Подводные камни
- Cartesian взрыв: если у обеих сторон по
user_idесть дубли — получитеm × nстрок на ключ. Всегдаvalidate=. - NaN в ключе никогда не матчатся друг с другом (как и в SQL) — пропадут даже при
inner. - Разные типы ключа (
int64vsobject) → 0 совпадений и пустойinner. Сверяйтеdtype. - После
leftjoin NaN в правых колонках означают не «нет данных», а «не нашёлся ключ» — это разные вещи. mergeмолчит, если ключ ничей — проверяйтеindicator='_merge'.
Эталонный ответ
inner пересечение, left/right сохраняют свою сторону, outer объединение. Всегда указывайте validate= и indicator=True, чтобы поймать «размножение» строк и пропавшие ключи.