Расходы рекламы в pandas: сверяем кабинет, оплаты и заказы
Рекламный кабинет показывает расход, биллинг — списания, а CRM — заказы. Если соединить три выгрузки построчно по каналу, расходы умножатся на число заказов. Соберём сверку на общей единице «день и канал» и отдельно увидим несовпадения источников.
У каждой таблицы своя детализация
В кабинете может быть несколько кампаний одного канала за день. В биллинге — несколько списаний. В заказах — отдельная покупка. Сначала каждую таблицу сворачиваем до общего ключа, затем соединяем результаты. validate="one_to_one" защищает именно получившиеся агрегаты.
Расход кабинета и списание не всегда обязаны совпадать ежедневно: возможны налоги, задержки и корректировки. Поэтому сверка показывает разницу, а её допустимое значение задаёт договор с бухгалтерией. В примере все суммы относятся к одной дате без налоговых расхождений.
Покрытие важнее красивого ROAS
Используем outer join: канал, который встречается только в одном источнике, должен остаться в отчёте. Пропуски расхода не заполняем нулём автоматически. Ноль означает подтверждённое отсутствие затрат, NaN — отсутствие сведений. Делить выручку на неизвестный расход нельзя.
import pandas as pd
ads = pd.DataFrame({"day":["2026-10-01"]*3,"channel":["search","search","social"],"spend":[100,150,200]})
bills = pd.DataFrame({"day":["2026-10-01"]*2,"channel":["search","social"],"paid":[250,190]})
orders = pd.DataFrame({"day":["2026-10-01"]*3,"channel":["search","search","direct"],"revenue":[400,600,300]})
keys = ["day","channel"]
a = ads.groupby(keys).spend.sum().reset_index()
b = bills.groupby(keys).paid.sum().reset_index()
o = orders.groupby(keys).revenue.sum().reset_index()
r = a.merge(b,on=keys,how="outer",validate="one_to_one").merge(o,on=keys,how="outer",validate="one_to_one")
r["billing_gap"] = r.spend-r.paid
print(r.sort_values("channel").to_string(index=False))
assert r.spend.sum() == 450
assert r.loc[r.channel.eq("social"),"billing_gap"].iloc[0] == 10
По search расходы сходятся: 250 из кабинета и 250 из биллинга. Social отличается на 10. Direct принёс 300 выручки, но отсутствует в рекламном расходе. У social нет связанной выручки: это может быть отсутствие заказов или неполная атрибуция. Проверять нужно источник, а не заменять оба случая одним нулём.
Из такой сверки получается рабочая очередь: выяснить расхождение биллинга, проверить разметку заказов, согласовать период признания затрат. Только после этого рассчитывают ROAS по каналам. При сравнении с бухгалтерской выручкой дополнительно проверяют возвраты и время учёта заказа: дата клика, оплаты и списания могут относиться к разным дням.
От сверки источников к решению по бюджету
Для рабочего отчёта сначала зафиксируйте таблицу соответствия каналов. В кабинете источник может называться social_ads, в CRM — paid_social, а в платёжном реестре — именем юридического лица. Эти строки не станут одним каналом от простого merge. Нормализацию выполняют до агрегации, сохраняя исходное название для расследования. Неизвестные значения лучше вынести в отдельную очередь, чем автоматически приписать крупнейшему каналу.
Следующая проверка относится к валюте и налогам. Если один кабинет отдаёт расход без НДС, а списание содержит НДС, ежедневная разница будет систематической. Можно привести оба источника к одной базе, но правило преобразования должно быть явным. Смешанные валюты также нельзя складывать до пересчёта по согласованному курсу. Иначе сверка покажет точное арифметическое отличие величин, которые изначально нельзя сравнивать.
После подтверждения расходов посмотрите на долю заказов с известным источником. Канал direct часто включает не только настоящие прямые заходы, но и потерянные метки. Если после изменения сайта direct резко вырос, а paid_search упал, это повод проверить передачу UTM и связь заказа с сессией. Перераспределять бюджет по такому отчёту рано: сначала нужно понять, изменилась эффективность рекламы или только запись источника.
Для сверки по дням допустимы временные расхождения. Например, кабинет обновляет вчерашний расход утром, а финансовое списание проходит через два дня. Поэтому полезно иметь два режима: оперативный отчёт с признаком незакрытого периода и закрытый месячный отчёт после поступления корректировок. Числа в них могут отличаться по понятной причине. Статус периода следует показывать в данных, чтобы последующее обновление не выглядело случайной правкой.
Решение о бюджете принимают после этих проверок. Для search можно посчитать отношение подтверждённой выручки к 250 расхода, но ещё предстоит учесть возвраты и маржу. Для social сначала разбирают разницу 10 и отсутствие заказов. Для direct уточняют, есть ли собственные затраты канала и насколько надёжна атрибуция. Такой порядок превращает сверку в список конкретных задач и защищает вывод от случайных особенностей трёх выгрузок.
При поиске расхождений полезна построчная сверка ключей и сумм: Как сверить два SQL-отчёта: одинаковые суммы могут скрывать ошибки.
Сверяем сумму до детализации
Расход исходного кабинета равен 450 и после агрегации остаётся 450. Биллинг даёт 440, поэтому разница всего периода равна 10. Этот контроль нужен даже при наличии проверки уникальности: она обнаруживает размножение ключей, но не замечает случайно исключённый канал. Сохраните исходные итоги по каждому источнику и сравнивайте их с итогами таблицы перед расчётом эффективности. Отрицательная разница также остаётся видимой: её нельзя обрезать до нуля перед суммированием.
Следующая рабочая задача
В «Практической аналитике данных» рекламные каналы — один из трёх прикладных кейсов наряду с продажами и удержанием. Вы отработаете путь от проверки таблиц до графика и рекомендации; расчёты доступны через pandas или SQL. Откройте программу курса «Практическая аналитика данных».
Продолжить на практике
- Практическая аналитика данных ↗
Превратите знания SQL или Python в аналитическую работу: проверяйте данные, считайте бизнес-метрики, стройте дашборды и объясняйте выводы на трёх прикладных кейсах.
