Объединение таблиц
Данные редко лежат в одной таблице. Заказы — отдельно, клиенты — отдельно, справочник товаров — отдельно. Чтобы ответить на вопрос «сколько потратил каждый клиент по имени», таблицы нужно соединить по общему столбцу — ключу. Это то же, что JOIN в базах данных.
merge — соединение по ключу
import pandas as pd
orders = pd.DataFrame({
"заказ": [1, 2, 3, 4],
"клиент": [10, 20, 10, 30],
"сумма": [500, 300, 200, 900],
})
clients = pd.DataFrame({
"клиент": [10, 20, 40],
"имя": ["Вера", "Аня", "Олег"],
})
print(pd.merge(orders, clients, on="клиент"))
заказ клиент сумма имя
0 1 10 500 Вера
1 3 10 200 Вера
2 2 20 300 Аня
Для каждой строки заказа нашлась строка клиента с тем же номером, и их столбцы склеились. Заказ клиента 30 пропал — его нет в справочнике. Клиент 40 тоже не попал — у него нет заказов.
Виды соединений
Параметр how задаёт, что делать со строками без пары:
how |
Какие ключи остаются |
|---|---|
"inner" (по умолчанию) |
только те, что есть в обеих таблицах |
"left" |
все ключи левой таблицы |
"right" |
все ключи правой таблицы |
"outer" |
все ключи из обеих |
Где пары не нашлось, в столбцах другой таблицы будет NaN:
full = pd.merge(clients, orders, on="клиент", how="left")
print(full)
# Олег попадёт в результат, у него «заказ» и «сумма» будут NaN
Пропуски часто заменяют: full["сумма"] = full["сумма"].fillna(0).
Если одному ключу соответствует несколько строк в каждой таблице, получится все комбинации — число строк может сильно вырасти. Перед соединением полезно проверить, что в справочнике ключи уникальны.
Если столбцы-ключи называются по-разному: pd.merge(a, b, left_on="client_id", right_on="id").
Сначала посчитать, потом соединить
Часто удобнее сначала сгруппировать одну таблицу, а потом присоединить результат к другой:
spent = orders.groupby("клиент")["сумма"].sum().reset_index()
report = pd.merge(clients, spent, on="клиент", how="left").fillna({"сумма": 0})
Так в отчёт попадут и клиенты без заказов — с нулём.
concat — таблицы друг под другом
Когда таблицы одинаковой структуры (отчёты за разные месяцы, данные из разных филиалов), их ставят одну под другой:
jan = pd.DataFrame({"товар": ["ручка"], "шт": [10]})
feb = pd.DataFrame({"товар": ["ручка", "тетрадь"], "шт": [7, 3]})
both = pd.concat([jan, feb], ignore_index=True)
ignore_index=True заново нумерует строки (иначе индексы 0 повторятся). С axis=1 таблицы ставятся рядом — по индексу строк.
Несколько таблиц в одном вводе
В задачах несколько таблиц могут прийти во входных данных подряд, разделённые особой строкой. Тогда читают весь ввод и режут его на части:
import io
import sys
parts = sys.stdin.read().split("---\n")
tables = [pd.read_csv(io.StringIO(p)) for p in parts]
io.StringIO(текст) превращает строку в «файл», который понимает read_csv.
Итог
pd.merge(a, b, on="ключ")— соединение строк с одинаковым ключом;how:inner— общие ключи,left/right— все ключи одной стороны,outer— все;- строки без пары получают
NaN, его заменяютfillna; - удобно сначала сгруппировать, потом соединить;
pd.concat([...], ignore_index=True)— таблицы друг под другом.