Малый бизнес

Как анализировать исторические данные маркетплейсов и не сойти с ума: грамотный расчет выручки — 26.09.26 13:51

Всем привет! По бэкграунду я инженер, и некоторое время назад решил запустить -проект — сервис для маркетплейсов. В этом блоге я планирую делиться реальным практическим опытом: от разработки до продаж. Буду рассказывать как про личный опыт, так и про опыт участников команды.

Эта статья — подробный технический разбор того, как проектировалась архитектура для расчета выручки для системы аналитики, на какие грабли наступали, почему классический теорвер и матстат из университетских учебников спотыкаются о сырые данные маркетплейсов и как в итоге удалось собрать архитектуру расчета продаж.

В статье не будет сырых простыней кода — только математика, архитектура, реальные проблемы на боевых данных и их решения.

Глава 1. Период наивности: Ozon, данные без истории и отзывы вместо продаж

Путь начинался с простой задачи: был массив данных с Ozon, сгруппированный по категориям. Данные представляли собой простой снимок текущего состояния карточек: название, текстовые характеристики, цена, рейтинг и число отзывов. Исторических данных не было в принципе. Не было временных рядов остатков, не было динамики цен. Ничего не было, только данные в один конкретный день. Но даже с таким набором можно работать.

Блочная архитектура анализа

Исходя из доступных данных и желаемого результата было решено разделить систему на модули:

1. Сегментация и поиск аномалий: выделение ценовых сегментов и составление топа товаров в каждом сегменте.

2. Анализ наименований: выявление слов-триггеров в заголовках карточек, коррелирующих с успехом товара.

3. Анализ структуры продавцов: оценка монополизации ниши через классические экономические метрики.

4. Оценка характеристик: легковесный ML.

Метрики концентрации: HHI и CR

Для оценки конкурентности мы использовали индекс Херфиндаля-Хиршмана (HHI) и коэффициент концентрации (CRₖ):

HHI = ∑ (sᵢ)²

где sᵢ — рыночная доля i-го продавца в процентах (0 ≤ sᵢ ≤ 100).

  • Если рынок поделен поровну между 100 продавцами, sᵢ = 1%, то:
    HHI = 100 × 1² = 100 (высокая конкуренция)

  • Если один монополист держит 70%, а остальные 30 делят остаток по 1%:
    HHI = 70² + 30 × 1² = 4930 (жесткая монополия)

HHI родился как экономический инструмент для измерения концентрации, но его математическое ядро — мера неравномерности распределения долей. Поэтому он естественным образом переносится на любые задачи, где есть набор взаимно исключающих категорий и их доли. В нашем случае мы использовали HHI по сути как готовый инструмент и обратились к его историческому назначению — определению неравномерности долей.

К нему добавили CRₖ — кумулятивная доля k крупнейших игроков:

CRₖ = ∑ sᵢ для i от 1 до k

В чем была главная проблема?

Единственной доступной метрикой спроса выступало число отзывов (F).

Мы понимали, что отзывы — это прокси-метрика. Причем крайне инертная:

— Карточка, продающаяся 4 года, накопила 5 000 отзывов, но за последний месяц могла не сделать ни одной продажи.

— Новинка с быстрым взлетом имеет 15 отзывов и 2 000 заказов за неделю, но в аналитике по отзывам она выглядит как абсолютный аутсайдер.

В общем-то, даже так результаты нам показались удовлетворительными — бились со здравым смыслом, и для нас это было достаточным показателем качества. Тем более мы осознавали, что с ограниченным набором данных и отсутствием исторических данных не получится сделать что-то принципиально иное — данных просто недостаточно.

Как анализировать исторические данные маркетплейсов и не сойти с ума: грамотный расчет выручки - 26.09.26 13:51

Пример результата аналитики для категории Смартфоны, который получился на данных без истории. По прокси-метрике отзывов настроили расчеты влияния тех или иных слов на спрос. Расчеты реализовали через токенизацию всех наименований.

Глава 2. «Теперь-то мы посчитаем всё точно!»: расчет продаж по складским остаткам и ценам Wildberries

В какой-то момент все-таки появились исторические данные, правда на WB. Ежедневные снимки складов и цен Wildberries — казалось, что святой Грааль найден. Больше никаких косвенных метрик! Из самого важного в распоряжении были данные:

  • product_id (SKU);

  • wh (идентификатор склада: Коледино, Электросталь, Казань и т.д.);

  • qty (физический остаток товара на складе);

  • price_product (история цен);

  • changed_at (временная метка фиксации).

Наивная модель восстановления продаж

Логика казалась железобетонной. Для каждого товара на складе строим временной ряд остатков Sₜ.

Изменение остатка между соседними днями t — 1 и t:

ΔSₜ = Sₜ − Sₜ₋₁

Интерпретация:

  • Если ΔSₜ < 0 — это продажа:
    Salesₜ = −ΔSₜ

  • Если ΔSₜ > 0 — это поставка:
    Supplyₜ = ΔSₜ

  • Если ΔSₜ = 0 — движения не было.

Казалось бы, просуммируй Salesₜ × Priceₜ по всем складам и дням — получишь выручку ниши или товара. Мы написали код агрегации, запустили расчет и… на выходе получили абсолютный бред.

Глава 3. Жестокое столкновение с реальностью: Почему дельта остатков дает сбой.

Первые же тесты на реальных категориях указали нам наше место.

Проблема №1: Дырчатый календарь и фантомные нули

Получить данные с миллионов карточек — процесс вероятностный:

— Бывают дни, когда данные просто отсутствуют (по техническим или иным причинам просто нет данных за этот день/промежуток).

— Бывают дни, когда конкретный артикул просто не вернулся в поисковой выдаче. Например, если товар закончился или временно скрыт.

Если 26-го числа у товара было 3 единицы, 27-го данные отсутствуют, а 28-го товара нет в выдаче — это 0 остатков или, может, продавец сменил фото карточки и товар ушел на модерацию?

Если считать отсутствие данных за 0, то:

1. День 1: остаток 3.

2. День 2: остаток 0 → записываем 3 продажи.

3. День 3: товар вернулся, остаток 3 → записываем поставку 3.

4. День 4: товар снова мигнул в выдаче → снова 3 продажи.

В итоге товар, лежащий мертвым грузом, «генерировал» продажи каждые два дня.

Проблема №2: «Синдром дачника»

На маркетплейсах тысячи селлеров работают по системе FBS (продажи со своего склада).

Представьте типичного продавца:

— У него карточка с 2 отзывами.

— На складе числится 50 чехлов для телефонов. Продаж нет неделями.

— В пятницу днем продавец решает уехать на выходные на дачу. Чтобы в субботу не упал заказ, который он не сможет вовремя упаковать (иначе WB влепит штраф за срыв логистики), он заходит в личный кабинет и руками выставляет остаток `0`.

— В понедельник он возвращается и выставляет остаток обратно: `50`.

Что видит наивный расчет?

— Пятница: остаток упал с 50 до 0 (ΔS = −50). Продано 50 штук!

— При цене чехла 800 рублей алгоритм рисует карточке с 2 отзывами 40 000 рублей выручки за день.

— Модуль аналитики моментально поднимает этот мусорный товар, искажая всю статистику категории, так как это место мог занять реально продающийся товар.

Мы назвали эту проблему «Синдром дачника» — конечно, не факт, что товар просто убирается руками и потому его остатки на складах скачут. Но в дальнейшем станет понятно, что нам в принципе и не нужно искать причину таких скачков.

Проблема №3: Загадочный график «трех пиков»

Мы открыли детальный отчет по категории аксессуаров для волос (реальный артикул из наших логов: «Крабики для волос маленькие», цена 181 руб., 1 858 отзывов, расчетная выручка 28 683 руб.).

Вот как выглядел график выручки по дням:

Как анализировать исторические данные маркетплейсов и не сойти с ума: грамотный расчет выручки - 26.09.26 13:51

Такой график получился, видно, что это просто три выброса — товар не может продаваться по 50 штук трижды, а в остальное время иметь ноль продаж.

  • Три дня (11, 16 и 19 июля) показывают всплески ровно по 9 000 – 9 500 рублей (~50–54 штуки проданных крабиков).

  • Во все остальные 27 дней месяца выручка — строгий ноль.

Почему живой товар с 1 800 отзывами продается строго три раза в месяц пачками по 50 штук, а между ними пустота? В этот момент стало ясно: мы моделируем не поведение покупателей, а какую-то техническую неточность.

Глава 4. Битва с ветряными мельницами: Почему сломался математический аппарат

Мы обратились к математике. У нас была возможность обратиться к человеку с сильным математическим бэкграундом, и первой мыслью было: «Сейчас мы почистим данные нормальными статистическими фильтрами и все будет в масле».

Мы сели проверять гипотезы:

Распределение Стьюдента и 3σ (трехсигмовые интервалы)

Мы пытались считать скользящее среднее и стандартное отклонение по продажам или остаткам и отрезать всё, что вылетает за доверительный интервал [μ − 3σ, μ + 3σ].

Почему развалилось:

1. Данные продаж на маркетплейсах не имеют нормального распределения.

Мы вообще в принципе не знаем, какое точно у нас распределение — оно сильно зависит от категории, а также от фильтров, которые мы выставим на набор данных. В ВУЗе мы обычно использовали статистику, имея некоторые допущения, гипотезы, предположения. От этого можно было оттолкнуться. А как определить в случае, когда мы не знаем распределение, верно ли мы применяем алгоритмы?

2. Экстремальные масштабы.

Всплеск продаж в день акции или после захода с рекламой может превышать среднее на 2–3 порядка. Если вы отсекаете по 2σ или 3σ, вы срезаете реальных лидеров рынка, но при этом пропускаете систематические выбросы у мелких товаров.

3. Проблема уровня агрегации (товар vs рынок).

  1. Если проверять выбросы внутри одного товара, то у товара-пустышки дроп с 50 до 0 — это единственное событие, у него выборочная дисперсия равна нулю. Такой алгоритм не считает это выбросом.

  2. А если проверять по всему рынку, то продажа 50 крабиков — обычное дело для крупного оптовика, но невозможная аномалия для селлера с нулевым рейтингом.

Переход к устойчивой (робастной) статистике: Log-IQR

Мы отказались от среднего и дисперсии в пользу медиан и квантильных размахов в логарифмическом пространстве.

Мы полагаем, что распределение цен и выручки мультипликативно, потому перевели метрики в логарифмическую шкалу:

y = ln(x + 1)

Затем считали интерквартильный размах ($IQR$):

IQR = Q₃ − Q₁

Верхняя граница отсечения выбросов:

Threshold_upper = Q₃ + k · IQR

Для цен в rule-based сегментации мы взяли мягкий коэффициент, а для кластеризации на основе нейросетей — более строгий. Здесь не так важно точное значение коэффициента, так как оно подбирается экспериментально.

Создание централизованного фильтра: Revenue Quality Filter

Чтобы остановить поток фантомной выручки, мы спроектировали трехуровневый алгоритм верификации качества. не удаляет товар из выборки, но помечает его флагом артефакта (is_artifact = True) и обнуляет расчетную выручку и продажи.

Как анализировать исторические данные маркетплейсов и не сойти с ума: грамотный расчет выручки - 26.09.26 13:51

Блок-схема расчетов

трех правил:

1. Правило 1 (Глобальный экстремум):

Отсекает технические выбросы данных, когда товару приписывалась выручка в сотни миллионов или миллиарды рублей.

2. Правило 2 (Аномальная выручка на один отзыв):

Для товаров из нижнего 5%-хвоста по отзывам (F ≤ Q₀.₀₅(F)) рассчитывается показатель удельной выручки:

R_unit = Revenue / (F + 1)

Если R_unit превышает квантильный порог референсной группы рынка (товары с F > Q₀.₀₅(F)), товар помечается флагом артефакта.

3. Правило 3 (Фантомные новички):

Если у товара 0 отзывов (F = 0), а его выручка превышает 5 медианных выручек зрелых товаров в своем ценовом бине:

Revenue > 5 · Median(Revenue_mature)

он признается артефактом.

Шок от реальных данных: десятки миллионов мусорных рублей

Когда мы прогнали этот фильтр на реальных выгрузках, результат все еще был далеко от идеала. Вот пример реального расчета:

Пример 1: Категория «Кинетический песок»

  • Всего проанализировано товаров: 1 581 SKU

  • Количество товаров, признанных артефактами: 742 SKU (почти 47% товаров из выборки!)

  • Сырая выручка, рассчитанная по дельте остатков: 59 818 625 руб.

  • Очищенная выручка после фильтра: 2 890 246 руб.

  • Срезано выручки: 56 928 379 руб. (95.2% расчетной выручки было мусором!**)

Вывод: 741 товар имел 0 отзывов, но алгоритм дельты нарисовал им 56 миллионов несуществующих продаж!

Пример 2: Категория «Аксессуары для волос»

  • Всего проанализировано товаров: 74 127 SKU

  • Товаров-артефактов: 5 710 SKU

  • Сырая выручка: 2 917 609 966 руб. (2.91 млрд руб.)

  • Очищенная выручка: 2 172 959 466 руб.

  • Срезано фантомной выручки: 744 650 500 руб. (почти три четверти миллиарда рублей мусора!)

Фильтр спасал от бреда, но оставалось чувство неудовлетворенности: мы просто зануляли половину рынка. Неужели нельзя восстановить истину?

Глава 5. Байесовское сглаживание: Приручение шума

Параллельно мы искали математический способ не бинарно вырезать товары, а плавно штрафовать метрики за недостаток данных.

Байесовское сглаживание в модуле Нейминга

В модуле текстового анализа названий наивное среднее тоже приводило к абсурду, хотя и не так часто: редкое слово (например, «экстра-супер-увлажнение»), встретившееся ровно 1 раз у товара-лидера, получало среднюю выручку в 500 000 рублей и вылетало на 1-е место рейтинга эффективности.

Мы применили формулу байесовского сглаживания с псевдонаблюдениями:

μ̂ᵢ = (C · m + ∑_{j=1}^{nᵢ} xᵢⱼ) / (C + nᵢ)

где:

  • ∑ xᵢⱼ — сумма метрики (выручки или отзывов) товаров, содержащих n-грамму i;

  • nᵢ — реальное число вхождений фразы;

  • m — глобальное среднее по всему рынку;

  • C — статистический вес эмпирических данных (число псевдонаблюдений).

Как анализировать исторические данные маркетплейсов и не сойти с ума: грамотный расчет выручки - 26.09.26 13:51

Если слово встретилось 3 раза, его оценка на 98.5% определяется рыночным фоном, и лишь при сотнях повторений слово завоевывает право называться драйвером продаж.

Не думаю, что про Байесовское сглаживание стоит подробно рассказывать. Это достаточно популярная вещь — можно найти много информации в интернете. Например, отличная статья.

Внедрение внутреннего индекса доверия

Мы решили адаптировать этот принцип к выручке товаров. Вместо жесткого отсечения мы ввели внутренний весовой коэффициент доверия к выручке на основе отзывов:

W(F) = W_min + (1 − W_min) · min(1, F / Q₇₅(F))

где:

  • W_min — минимальный вес доверия (0 < W_min < 1);

  • F — количество отзывов карточки;

  • Q₇₅(F) — 75-й перцентиль отзывов по рынку.

Внутренняя метрика использовалась для ранжирования карточек в выдаче, не позволяя товарам без валидации на основе данных группы пробиваться в топы.

Но оставался главный нерешенный вопрос: откуда всё-таки брались те загадочные пачки продаж по 44, 50, 53 штуки?

Глава 6. Момент истины: Секрет, который обнулил все расчеты по остаткам (как кэп остатков ломает аналитику)

Аналитика по дельте остатков системно дает сбой, поскольку интерфейс Wildberries кэпирует остатки в корзине, превращая колебания лимита в ложные продажи.

Конец июля 2026 года. Очередная ночная сессия дебага логов и поиска закономерностей.

Мы взяли один из тестовых аккаунтов селлера, загрузили на склад 100 единиц товара и открыли карточку в браузере как обычный покупатель. Нажали «Добавить в корзину» и попробовали выкрутить счетчик количества на максимум.

И тут наступил шок: Wildberries кэпирует остатки на витрине!

Оказалось, что интерфейс корзины Wildberries не показывает реальный остаток товара на складе, если он превышает определенный лимит. На витрине отдается искусственно обрезанное число. Оно колеблется в динамическом диапазоне (например, от 40 до 60 штук).

Более того, это значение может динамически меняться в зависимости от геолокации, типа склада, сессии пользователя или иных параметров.

Что это значило для нашего пайплайна?

Представьте:

1. У продавца на складе лежит 5 000 единиц товара.

2. Попытка узнать остатки: qty = 54 (сработал витринный кэп).

3. На следующий день стучимся на витрину снова, но получаем другой лимит: qty = 44.

4. Наш алгоритм делает расчет: ΔS = 44 — 54 = -10. Зафиксировано 10 продаж!

5. На третий день получаем qty = 53. Алгоритм видит увеличение остатка ⟹ считает это поставкой.

6. На четвертый день карточка на секунду выпала из выдачи: qty = 0. Алгоритм радостно пишет: продано 53 штуки!

Мы неделями искали идеальные формулы математической статистики, чтобы победить шум, который не являлся шумом на самом деле.

Считать продажи вычитанием складских остатков на Wildberries — это попытка измерить глубину линейкой, длина которой произвольно меняется.

Глава 7. Архитектурный разворот: Как считать продажи, если остаткам верить нельзя

Осознав природу данных, мы совершили фундаментальный разворот в архитектуре.

Мы вернулись к отзывам, но не в их примитивном виде, а через иерархическую систему калибровки продаж продавца.

Как анализировать исторические данные маркетплейсов и не сойти с ума: грамотный расчет выручки - 26.09.26 13:51

Блок-схема расчета выручки через отзывы

В чем суть нового подхода?

Есть не только данные по товарам, но и периодические снимки по продавцам в целом:

  • sold_products_count — общее число заказов / проданных товаров всего магазина селлера;

  • product_feedbacks_count — суммарное число отзывов на всех товарах селлера.

За любой интервал времени для продавца известны два фундаментальных макро-показателя:

  • Сколько реально продал весь магазин: ΔS_seller;

  • Сколько реально новых отзывов получил весь магазин: ΔF_seller.

Это дает нам фактическую эмпирическую конверсию отзывов в заказы именно для этого продавца в этот конкретный календарный период:

K = ΔS_seller / ΔF_seller

При расчете выручки через отзывы есть тоже свои нюансы. Не должно быть никаких догадок из серии «на WB один отзыв приходится в среднем на 30–50 покупок». Такие догадки никуда не годятся. Для бренда дешевых носков этот коэффициент может быть равен 80, а для премиальной бытовой техники — 12.

Спуск на уровень товара

Когда у конкретного товара i, принадлежащего данному продавцу, за интервал времени вырастает число отзывов на ΔF_i, его доля в общем пуле продаж магазина определяется пропорцией прироста его отзывов к общему приросту отзывов селлера:

Raw_Sales_i = ΔS_seller · (ΔF_i / ΔF_seller) = K · ΔF_i

Целочисленное квантование: Метод Гамильтона

Поскольку Raw_Sales_i получается дробным числом, а товар измеряется в целых штуках, мы применили классический метод распределения мест Гамильтона (метод наибольших остатков, allocate_integer_sales):

  1. Каждому товару с положительным приростом отзывов гарантированно отдается целая часть (но не менее 1 шт):
    Base_Sales_i = ⌊Raw_Sales_i⌋

  2. Оставшийся нераспределенный пул заказов:
    R = ΔS_seller − ∑ᵢ Base_Sales_i
    поочередно раздается товарам с максимальной дробной частью
    Raw_Sales_i − ⌊Raw_Sales_i⌋

Консервативная привязка цен

Чтобы исключить раздувание выручки, если продавец кратковременно менял цену (например, задрал перед акцией), мы сопоставляем интервал продажи с историей изменения цен:

Price_calc = min_{t ∈ T} (Price_t)

Берется консервативный минимум цены за интервал наблюдения.

Результат архитектурного перехода

  1. Исчезли фантомные миллионы: товары с 0 отзывов физически больше не могут получить ни единой продажи из-за скачков складских лимитов.

  2. Ушел эффект кэпирования корзины: алгоритм вообще не смотрит на остаток товара, если тот подвержен витринным ограничениям.

  3. Сохранилась адекватная динамика: если селлер запустил рекламу и пошли продажи с отзывами, они пропорционально и честно распределяются между его SKU.

Как анализировать исторические данные маркетплейсов и не сойти с ума: грамотный расчет выручки - 26.09.26 13:51

Вот так стал выглядеть график продаж через данные об отзывах по товару из категории Зоотовары / Для собак / Ветаптека. К тому же, лидеры рынка стали определяться корректно.

Глава 8. Чек-лист по расчету аналитики маркетплейсов

Сравнительный анализ методов расчета продаж

Как анализировать исторические данные маркетплейсов и не сойти с ума: грамотный расчет выручки - 26.09.26 13:51

Чек-лист: Как построить надежный пайплайн аналитики

1. Никогда не доверяйте исходным числам:

Витринные значения могут быть срезаны кэпами, кэшем или поведением корзины.

2. Забудьте про стандартные распределения:

Никаких нормальных кривых и 3σ. Используйте только непараметрические и робастные статистики: квантили (Q_p), межквартильный размах (IQR), медианы и логарифмирование (ln(x + 1)).

3. Внедряйте многоуровневую верификацию артефактов и выбросов:

Если ваш алгоритм насчитал товару с 0 отзывов миллион рублей выручки — в 99.9% случаев неправ ваш алгоритм, а не покупатели смели склад.

4. Используйте байесовское сглаживание — оно реально работает:

Редкие события должны притягиваться к среднему по рынку. Для текстовых признаков (нейминг, теги) и для метрик надежности используйте фиктивные псевдонаблюдения.

5. Связывайте микро-уровень с макро-уровнем:

Если метрика на микро-уровне дает сомнительный сигнал, проверяйте и калибруйте ее через родительскую сущность (магазин, категорию, бренд).

Заключение: Почему ни один внешний сервис не знает 100% правды

Если вам в рекламе очередного сервиса аналитики заявляют: «Мы знаем точные продажи каждого товара на Wildberries с точностью до одной копейки по нашим секретным данным» — теперь вы знаете, что эти секретные данные могут оказаться не очень верными.

Внешняя аналитика маркетплейсов — это не про точность до рубля, из открытых источников такое достать невозможно. Это про понимание структуры рынка, поиск реальных закономерностей и отсечение информационного мусора.

Когда мы перестали пытаться выжать из дырявых складских остатков несуществующую точность и построили математически выверенную модель, хоть и не дающую точность до рубля, система наконец начала выдавать отчеты, на которые можно опереться при принятии реальных бизнес-решений.

Внешняя аналитика — это всегда вероятностная модель и баланс компромиссов.

А как вы боретесь с выбросами и аномалиями в данных и какими средствами аналитики пользуетесь? Делитесь в комментариях своим опытом — будет интересно обсудить!

Какие темы на пути к построению своего IT-проекта было бы интересно увидеть в следующих постах?

Проверить достоверность описанной методики и оценить результат проделанной работы можно в инструменте аналитики моего проекта.

Источник

Нажмите, чтобы оценить!
[Общий: 0 Средний: 0]

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

1 × два =

Кнопка «Наверх»