Отчёт в pandas: groupby, agg и merge со справочником

Для отчёта часто нужны две операции: сначала агрегировать факты через groupby().agg(), затем присоединить атрибуты из справочника через merge. Именованная агрегация позволяет сразу задать понятные названия итоговых столбцов.

Зачем указывать validate при merge

Если справочник должен содержать одну строку на ключ, validate="many_to_one" обнаружит его дубли. Без этой проверки соединение может размножить строки и исказить итоговые суммы. После агрегации и соединения проверьте число строк, названия столбцов и наличие отсутствующих ключей.

Пример на других данных

import pandas as pd
sales = pd.DataFrame({"shop": [1, 1, 2], "value": [40, 60, 30]})
shops = pd.DataFrame({"shop": [1, 2], "city": ["Омск", "Томск"]})
totals = sales.groupby("shop", as_index=False).agg(revenue=("value", "sum"))
report = totals.merge(shops, on="shop", how="left", validate="many_to_one")
print(report[["city", "revenue"]].to_dict(orient="records"))

Результат:

[{'city': 'Омск', 'revenue': 100}, {'city': 'Томск', 'revenue': 30}]

Решите задачу

Ниже — условие и редактор Python с проверкой без регистрации. Пример выше показывает приём на других данных; для задачи соблюдайте её формат ввода и результата. Курс NumPy и pandas помогает пройти темы по порядку.

Финальный отчёт: groupby + agg, merge с validate, вычисляемый столбец и спецификация

Вы реализуете функцию build_client_report, которая принимает две готовые таблицы и возвращает финальный аналитический отчёт.

Что уже дано

Проверяющая система вызывает build_client_report(orders, clients), передавая два готовых pd.DataFrame:

  • orders — таблица заказов со столбцами 'order_id' (int), 'client_id' (int), 'amount' (float). Уже подготовлена: без пропусков, без дублей по 'order_id'.
  • clients — справочник клиентов со столбцами 'client_id' (int), 'segment' (str). Уникальна по 'client_id'.

Что нужно сделать

Реализуйте функцию build_client_report(orders, clients), которая выполняет ровно четыре шага и возвращает итоговый pd.DataFrame.

Шаг 1. Named aggregation. Сгруппируйте orders по 'client_id' с as_index=False и вычислите за один вызов .agg():

  • order_count=('order_id', 'count') — число заказов клиента;
  • total_amount=('amount', 'sum') — суммарная сумма заказов.

Сохраните результат в переменную agg.

Шаг 2. Merge с validate. Соедините agg и clients через pd.merge с параметрами:

  • on='client_id'
  • how='left'
  • validate='many_to_one'

Сохраните результат в переменную result.

Шаг 3. Вычисляемый столбец. Добавьте в result столбец 'avg_amount' как векторное выражение result['total_amount'] / result['order_count'].

Шаг 4. Спецификация. Оставьте в result ровно эти столбцы в указанном порядке:

['client_id', 'segment', 'order_count', 'total_amount', 'avg_amount']

Отсортируйте строки по 'total_amount' по убыванию (ascending=False) и сбросьте индекс через reset_index(drop=True).

Верните итоговый result.

Ввод и вывод

stdin не используется. Печатать через print в stdout ничего не нужно.

Проверяющая система вызывает build_client_report(orders, clients) и проверяет возвращаемое значение. Функция принимает два аргумента:

  • orders — pd.DataFrame с заказами;
  • clients — pd.DataFrame-справочник клиентов.

Функция должна вернуть pd.DataFrame с пятью столбцами в порядке спецификации, отсортированный по 'total_amount' по убыванию, с чистым RangeIndex.

Пример использования

orders = pd.DataFrame({
 'order_id': [1, 2, 3],
 'client_id': [10, 10, 20],
 'amount': [100.0, 50.0, 200.0],
})
clients = pd.DataFrame({
 'client_id': [10, 20],
 'segment': ['standard', 'premium'],
})
result = build_client_report(orders, clients)
print(result.to_dict(orient='records'))

Результат:

[{'client_id': 20, 'segment': 'premium', 'order_count': 1, 'total_amount': 200.0, 'avg_amount': 200.0}, {'client_id': 10, 'segment': 'standard', 'order_count': 2, 'total_amount': 150.0, 'avg_amount': 75.0}]
РешениеPython

Без регистрации. Гостевая проверка не сохраняет прогресс. Для сохранения перейдите к уроку.

Отправьте решение, чтобы увидеть результаты тестов.

Связанные задачи