Нашли ошибку?
среднийpandas 3.0.6

merge: ключи и проверки

Ключи с разными именами, одинаковые столбцы в обеих таблицах, проверка уникальности ключей и объединение по индексу.

Нужно знать:merge: виды соединений

Содержание статьи

Коротко

  • Ключи называются по-разному — left_on="customer", right_on="client_id". По индексу — left_index=True / right_index=True.
  • Одноимённые столбцы, которые не являются ключом, получают суффиксы _x и _y; свои — suffixes=("_a", "_b").
  • indicator=True добавляет столбец _merge: both, left_only, right_only — удобно искать строки без пары.
  • validate="one_to_one", "one_to_many", "many_to_one" проверяет уникальность ключей и падает, если она нарушена.
  • df.join(other) — короткая форма merge по индексу other.

Синтаксис

left.merge(right, left_on="a", right_on="b", how="left")
left.merge(right, left_on="a", right_index=True)
left.merge(right, on="k", suffixes=("_x", "_y"), indicator=False, validate=None)
left.join(right, on=None, how="left")

Параметры

ПараметрЧто делаетПо умолчанию
left_on / right_onключи с разными именами в левой и правой таблицеNone
left_index / right_indexиспользовать индекс как ключFalse
suffixesсуффиксы для одноимённых столбцов("_x", "_y")
indicatorдобавить столбец _merge с источником строкиFalse
validate"one_to_one", "one_to_many", "many_to_one", "many_to_many"None

Примеры

Данные для примеровиспользуются во всех примерах ниже
clients = pd.DataFrame({"client_id": [1, 2, 3], "name": ["Аня", "Борис", "Вика"], "city": ["Омск", "Тула", "Сочи"]})
orders = pd.DataFrame({"order": [10, 11, 12], "customer": [2, 3, 4], "city": ["Тула", "Москва", "Омск"]})
Ключи с разными именами
orders.merge(clients, left_on="customer", right_on="client_id", how="left")
Вывод
   order  customer  city_x  client_id   name city_y
0     10         2    Тула        2.0  Борис   Тула
1     11         3  Москва        3.0   Вика   Сочи
2     12         4    Омск        NaN    NaN    NaN
Одноимённые столбцы
orders.merge(clients, left_on="customer", right_on="client_id",
             suffixes=("_delivery", "_client"))
Вывод
   order  customer city_delivery  client_id   name city_client
0     10         2          Тула          2  Борис        Тула
1     11         3        Москва          3   Вика        Сочи
Откуда строка: indicator
res = orders.merge(clients, left_on="customer", right_on="client_id", how="outer", indicator=True)
res[["order", "name", "_merge"]]
Вывод
   order   name      _merge
0    NaN    Аня  right_only
1   10.0  Борис        both
2   11.0   Вика        both
3   12.0    NaN   left_only
Ключ в индексе правой таблицы
cl = clients.set_index("client_id")
orders.merge(cl[["name"]], left_on="customer", right_index=True, how="left")
Вывод
   order  customer    city   name
0     10         2    Тула  Борис
1     11         3  Москва   Вика
2     12         4    Омск    NaN
join — объединение по индексу
cl = clients.set_index("client_id")
orders.set_index("customer").join(cl[["name"]], how="left")   # join — merge по индексу
Вывод
          order    city   name
customer
2            10    Тула  Борис
3            11  Москва   Вика
4            12    Омск    NaN
Несколько ключей
plan = pd.DataFrame({"city": ["Омск", "Омск"], "month": ["янв", "фев"], "plan": [100, 120]})
fact = pd.DataFrame({"city": ["Омск", "Омск"], "month": ["фев", "янв"], "fact": [130, 95]})
plan.merge(fact, on=["city", "month"])            # пара ключей
Вывод
   city month  plan  fact
0  Омск   янв   100    95
1  Омск   фев   120   130

Подводные камни

Неожиданные дубликаты в справочнике

Повтор в «справочной» таблице молча размножает строки фактов. validate превращает это в явную ошибку.

validate='many_to_one'ошибка: MergeError
dup = pd.concat([clients, clients.head(1)])        # клиент 1 записан дважды
orders.merge(dup, left_on="customer", right_on="client_id", validate="many_to_one")
Ошибка
MergeError: Merge keys are not unique in right dataset; not a many-to-one merge

Duplicates in right:
  client_id
         1 ...

Два столбца-ключа в результате

С left_on / right_on оба ключа остаются в результате (customer и client_id). Лишний удалите через drop(columns=…).