</>
Topic 6 of 7

Course materials are currently available in Russian only.

Объединение таблиц

Данные редко лежат в одной таблице. Заказы — отдельно, клиенты — отдельно, справочник товаров — отдельно. Чтобы ответить на вопрос «сколько потратил каждый клиент по имени», таблицы нужно соединить по общему столбцу — ключу. Это то же, что 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) — таблицы друг под другом.