Левое и правое объединение
Выполняйте левые и правые объединения, сохраняя все строки одной таблицы и сопоставляя записи из другой.
«Левое и правое объединение» — бесплатный урок Pandas & NumPy Academy на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Pandas & NumPy Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Pandas & NumPy Academy содержит 4 уроков всего.
Асимметричные объединения
Внутреннее и внешнее объединения рассматривают оба DataFrame симметрично. Но часто требуется сохранить все записи из одной таблицы, дополнив их данными из другой. Для этого используются левые объединения и правые объединения. Такие асимметричные объединения очень распространены в аналитике: сохранить все транзакции и добавить названия товаров, если они доступны; сохранить всех пользователей и добавить дату их последней покупки, если она есть.
Левое объединение: сохранение всех строк слева
Левое объединение (how='left') сохраняет каждую строку из левого DataFrame. Для строк, у которых найден совпадающий ключ в правом DataFrame, в правые столбцы записываются совпавшие значения. Для строк без совпадения в правые столбцы записывается NaN. Количество строк в результате всегда равно количеству строк в левом DataFrame (если ключи не дублируются).
import pandas as pd
orders = pd.DataFrame({
'order_id': [1, 2, 3, 4],
'customer_id': [101, 102, 101, 999],
'amount': [250, 80, 320, 150]
})
customers = pd.DataFrame({
'customer_id': [101, 102, 103],
'name': ['Alice', 'Bob', 'Carol']
})
result = pd.merge(orders, customers, on='customer_id', how='left')
print(result)
# All 4 orders kept; order with customer_id=999 gets NaN for nameСтруктура результата левого объединения
После левого объединения строки из левого DataFrame, для которых не найдено совпадение в правом, будут содержать NaN во всех столбцах, пришедших из правой таблицы. С помощью логического фильтра по столбцу правой таблицы можно найти такие строки и подсчитать, сколько левых строк не имели совпадения, — это полезная проверка качества данных.
result = pd.merge(orders, customers, on='customer_id', how='left')
print(result)
# order_id customer_id amount name
# 0 1 101 250 Alice
# 1 2 102 80 Bob
# 2 3 101 320 Alice
# 3 4 999 150 NaN <- no matching customer
# Count unmatched
unmatched = result['name'].isna().sum()
print(f'{unmatched} orders have no customer record')Когда использовать левое объединение
Левые объединения подходят, когда левый DataFrame является основной таблицей, а правая таблица содержит дополнительные данные. Распространённые случаи: дополнение таблицы фактов таблицей измерений (заказы и названия товаров), добавление необязательных метаданных (пользователи и данные профиля) или расчёт показателей для всех записей, даже если поиск соответствия завершился неудачей. В аналитическом коде левые объединения встречаются гораздо чаще правых.
# Realistic pattern: enrich all products with optional category data
products = pd.DataFrame({'sku': ['A1', 'B2', 'C3'], 'price': [10, 20, 15]})
categories = pd.DataFrame({'sku': ['A1', 'C3'], 'category': ['Tools', 'Home']})
# Keep all products; add category where available
enriched = pd.merge(products, categories, on='sku', how='left')
print(enriched)
# sku price category
# 0 A1 10 Tools
# 1 B2 20 NaN
# 2 C3 15 HomeПравое объединение: сохранение всех строк справа
Правое объединение (how='right') является зеркальным отражением левого: оно сохраняет каждую строку из правого DataFrame и записывает NaN в столбцы левой таблицы, если совпадение не найдено. Правые объединения используются реже, поскольку того же результата всегда можно достичь, поменяв DataFrames местами и применив левое объединение, что понятнее читателям.
# Right join: keep all customers, attach orders where they exist
result = pd.merge(orders, customers, on='customer_id', how='right')
print(result)
# All 3 customers appear; Carol (103) has NaN for order_id and amount
# Equivalent left join (swap arguments):
result2 = pd.merge(customers, orders, on='customer_id', how='left')
# Same data, just column order differsСравнение всех четырёх типов объединения
Четыре типа объединения различаются только тем, какие строки со стороны без совпадений сохраняются. inner: только совпавшие строки. outer: все строки с обеих сторон. left: все строки слева. right: все строки справа. Для несовпадающих записей столбцы отсутствующей стороны заполняются значениями NaN. Правильный выбор крайне важен, чтобы не удалять и не дублировать записи незаметно.
# Summary table
# how='inner' : rows in BOTH tables
# how='left' : ALL left rows + matched right
# how='right' : matched left + ALL right rows
# how='outer' : ALL left rows + ALL right rows
# Test each
for how in ['inner', 'left', 'right', 'outer']:
r = pd.merge(orders, customers, on='customer_id', how=how)
print(f'{how}: {len(r)} rows')Заполнение NaN в результатах левого объединения
После левого объединения несовпадающие строки содержат NaN в столбцах правой таблицы. Часто их требуется заменить разумными значениями по умолчанию — например, 'Unknown' для отсутствующей категории или 0 для отсутствующего количества. Используйте fillna() для результата или передайте fill_value в арифметические операции, выполняемые после объединения.
result = pd.merge(products, categories, on='sku', how='left')
result['category'] = result['category'].fillna('Uncategorised')
print(result)
# sku price category
# 0 A1 10 Tools
# 1 B2 20 Uncategorised
# 2 C3 15 HomeАнтиобъединение слева: строки без совпадений
Полезный шаблон, который напрямую не поддерживается параметром how, — это антиобъединение: сохраняются только левые строки, для которых нет совпадения в правой таблице. Реализуйте его с помощью левого объединения и indicator=True, а затем отфильтруйте строки по условию _merge == 'left_only'. Это идеально подходит для поиска потерянных записей, новых элементов, отсутствующих в справочном списке, или транзакций, отсутствующих в журнале.
# Anti-join: orders with no matching customer record
result = pd.merge(orders, customers, on='customer_id',
how='left', indicator=True)
unmatched_orders = result[result['_merge'] == 'left_only'].drop(columns='_merge')
print(unmatched_orders)
# order_id customer_id amount name
# 3 4 999 150 NaNСохранение количества строк при левом объединении
Если в правом DataFrame ключи уникальны, левое объединение гарантированно сохраняет точное количество строк в левой таблице. Однако если в правой таблице есть дублирующиеся значения ключа, левое объединение умножает строки так же, как внутреннее. Всегда проверяйте, что количество строк в результате совпадает с количеством строк в левой таблице, если ожидается связь «один ко многим».
# Right table has duplicate keys -> row multiplication
orders_small = pd.DataFrame({'id': [1, 2], 'amount': [100, 200]})
multi_customer = pd.DataFrame({
'id': [1, 1], # duplicate!
'contact': ['Alice', 'Alice2']
})
result = pd.merge(orders_small, multi_customer, on='id', how='left')
print(len(result)) # 3 rows! order 1 appears twice
print(result)Практический шаблон левого объединения
Вот полный рабочий процесс из практики: начните с журнала транзакций, выполните левое объединение с каталогом товаров, чтобы получить названия, а затем левое объединение с таблицей клиентов, чтобы получить имена. Замените отсутствующие результаты поиска значениями по умолчанию. Цепочка левых объединений гарантирует сохранение каждой строки транзакций, даже если запись о товаре или клиенте отсутствует в справочных таблицах.
transactions = pd.DataFrame({
'txn_id': [1, 2, 3],
'cust_id': [10, 11, 99],
'prod_id': [20, 21, 20],
'total': [50, 30, 70]
})
custs = pd.DataFrame({'cust_id': [10, 11], 'cust_name': ['Alice', 'Bob']})
prods = pd.DataFrame({'prod_id': [20, 21], 'prod_name': ['Widget', 'Gadget']})
result = (
transactions
.merge(custs, on='cust_id', how='left')
.merge(prods, on='prod_id', how='left')
)
print(result)Выбор между левым и внутренним объединением
Выбор между левым и внутренним объединением — это решение, связанное с бизнес-логикой: следует ли сохранять записи без найденного соответствия или незаметно удалять их? Используйте левое объединение, если отсутствие соответствия допустимо и требуется сохранить все основные записи. Используйте внутреннее объединение, если отсутствие соответствия означает, что запись недействительна и её следует исключить из анализа. Всегда документируйте свой выбор и его причину.
# Left join: keep all transactions (some may have no product name)
result_left = pd.merge(transactions, prods, on='prod_id', how='left')
print('Left join rows:', len(result_left)) # same as transactions
# Inner join: only transactions with known product
result_inner = pd.merge(transactions, prods, on='prod_id', how='inner')
print('Inner join rows:', len(result_inner)) # may be fewerБыстрая проверка
Проверьте, насколько хорошо Вы поняли левые и правые объединения из этого урока.
Итоги урока
В этом уроке Вы узнали, что левое объединение сохраняет все строки из левого DataFrame, заполняя правые столбцы значением NaN для несовпадающих строк; правое объединение является его зеркальным отражением; шаблон антиобъединения с использованием indicator=True находит левые строки без совпадения справа; а выбор между левым и внутренним объединением является решением, связанным с бизнес-логикой. Далее Вы изучите объединение DataFrames по индексу, а не по столбцу.
Часто задаваемые вопросы
Урок «Левое и правое объединение» бесплатный?
Да — полный текст урока «Левое и правое объединение» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Pandas & NumPy Academy, подпишись на CoddyKit PRO. Курс Pandas & NumPy Academy содержит 4 уроков всего.
Чему я научусь в уроке «Левое и правое объединение»?
Выполняйте левые и правые объединения, сохраняя все строки одной таблицы и сопоставляя записи из другой. Ты практикуешь Pandas & NumPy Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Pandas & NumPy Academy?
Предыдущий опыт не требуется. Pandas & NumPy Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.
Сколько времени занимает урок «Левое и правое объединение»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Pandas & NumPy Academy?
Да. Каждый урок Pandas & NumPy Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- pd.concat для объединения DataFrames
- pd.merge: внутреннее и внешнее объединение
- Левое и правое объединение
- Объединение по индексу