Эта статья — подробный технический разбор того, как мы проектировали архитектуру для расчета выручки для системы аналитики RAMSTAT, на какие грабли наступали, почему классический теорвер и матстат из университетских учебников спотыкаются о сырые данные маркетплейсов и как мы в итоге собрали архитектуру расчета продаж.
В статье не будет сырых простыней кода — только математика, архитектура, реальные проблемы на боевых данных и их решения.
Глава 1. Период наивности: Ozon, данные без истории и отзывы вместо продаж
Путь начинался с простой задачи: был массив данных с Ozon, сгруппированный по категориям. Данные представляли собой простой снимок текущего состояния карточек: название, текстовые характеристики, цена, рейтинг и число отзывов. Исторических данных не было в принципе. Не было временных рядов остатков, не было динамики цен. Ничего не было, только данные в один конкретный день. Но даже с таким набором можно работать.
Блочная архитектура анализа
Исходя из доступных данных и желаемого результата было решено разделить систему на модули:
-
Сегментация и поиск аномалий: выделение ценовых сегментов и составление топа товаров в каждом сегменте.
-
Анализ наименований: выявление слов-триггеров в заголовках карточек, коррелирующих с успехом товара.
-
Анализ структуры продавцов: оценка монополизации ниши через классические экономические метрики.
-
Оценка характеристик: легковесный ML.
Метрики концентрации: HHI и CR
Для оценки конкурентности мы использовали индекс Херфиндаля-Хиршмана () и коэффициент концентрации
:
где — рыночная доля
-го продавца в процентах. Если рынок поделен поровну между 100 продавцами,
(высокая конкуренция). Если один монополист держит 70%, а остальные 30 делят остаток,
(жесткая монополия).
HHI родился как экономический инструмент для измерения концентрации, но его математическое ядро — мера неравномерности распределения долей. Поэтому он естественным образом переносится на любые задачи, где есть набор взаимно исключающих категорий и их доли. В нашем случае мы использовали HHI по сути, как готовый инструмент и обратились к его историческому назначению — определению неравномерности долей.
К нему добавили — кумулятивная доля
крупнейших игроков:
В чем была главная проблема?
Единственной доступной метрикой спроса выступало число отзывов ().
Мы понимали, что отзывы — это прокси-метрика. Причем крайне инертная:
-
Карточка, продающаяся 4 года, накопила 5 000 отзывов, но за последний месяц могла не сделать ни одной продажи.
-
Новинка с быстрым взлетом имеет 15 отзывов и 2 000 заказов за неделю, но в аналитике по отзывам она выглядит как абсолютный аутсайдер.
В общем-то, даже так результаты нам показались удовлетворительными — бились со здравым смыслом и для нас это было достаточным показателем качества. Тем более, мы осознавали, что с ограниченным набором данных и отсутствием исторических данных не получится сделать что-то принципиально иное — данных просто недостаточно.
Глава 2. «Теперь-то мы посчитаем всё точно!»: расчет продаж по складским остаткам и ценам Wildberries
В какой-то момент все-таки появились исторические данные, правда на WB. Ежедневные снимки складов и цен Wildberries, казалось, что святой Грааль найден. Больше никаких косвенных метрик! Из самого важного в распоряжении были данные:
-
product_id(SKU); -
wh(идентификатор склада: Коледино, Электросталь, Казань и т.д.); -
qty(физический остаток товара на складе); -
price_product(история цен); -
changed_at(временная метка фиксации).
Наивная модель восстановления продаж
Логика казалась железобетонной. Для каждого товара на складе
строим временной ряд остатков
.
Изменение остатка между соседними днями и
:
Интерпретация:
-
Если
— это продажа:
-
Если
— это поставка:
-
Если
— движения не было.
Казалось бы, просуммируй по всем складам и дням — получишь выручку ниши или товара. Мы написали код агрегации, запустили расчет и… на выходе получили абсолютный бред.
Глава 3. Жестокое столкновение с реальностью: Почему дельта остатков дает сбой
Первые же тесты на реальных категориях указали нам наше место.
Проблема №1: Дырчатый календарь и фантомные нули
Получить данные с миллионов карточек — процесс вероятностный:
-
Бывают дни, когда данные просто отсутствуют (по техническим или иным причинам просто нет данных за этот день/промежуток).
-
Бывают дни, когда конкретный артикул просто не вернулся в поисковой выдаче. Например, если товар закончился.
Если 26-го числа у товара было 3 единицы, 27-го данные отсутствуют, а 28-го товара нет выдаче — это 0 остатков или может продавец сменил фото карточки и товар ушел на модерацию?
Если считать отсутствие данных за 0, то:
-
День 1: остаток 3.
-
День 2: остаток 0
записываем 3 продажи.
-
День 3: товар вернулся, остаток 3
записываем поставку 3.
-
День 4: товар снова мигнул в выдаче
снова 3 продажи.
В итоге товар, лежащий мертвым грузом, «генерировал» продажи каждые два дня.
Проблема №2: «Синдром дачника»
На маркетплейсах тысячи селлеров работают по системе FBS (продажи со своего склада).
Представьте типичного продавца:
-
У него карточка с 2 отзывами.
-
На складе числится 50 чехлов для телефонов. Продаж нет неделями.
-
В пятницу днем продавец решает уехать на выходные на дачу. Чтобы в субботу не упал заказ, который он не сможет вовремя упаковать (иначе WB влепит штраф за срыв логистики), он заходит в личный кабинет и руками выставляет остаток 0.
-
В понедельник он возвращается и выставляет остаток обратно: 50.
Что видит наивный расчет?
-
Пятница: остаток упал с 50 до 0.
. Продано 50 штук!
-
При цене чехла 800 рублей алгоритм рисует карточке с 2 отзывами 40 000 рублей выручки за день.
-
Модуль аналитики моментально поднимает этот мусорный товар, искажая всю статистику категории, так как это место мог занять реально продающийся товар.
Мы назвали эту проблему «Синдром дачника» — конечно, не факт, что товар просто убирается руками и потому его остатки на складах скачут. Но в дальнейшем будет понятно, что нам в принципе и не нужно искать причину таких скачков.
Проблема №3: Загадочный график «трех пиков»
Мы открыли детальный отчет по категории аксессуаров для волос (реальный артикул из наших логов: Крабики для волос маленькие, цена 181 руб., 1 858 отзывов, расчетная выручка 28 683 руб.).
Вот как выглядел график выручки по дням:
Три дня (11, 16 и 19 июля) показывают всплески ровно по 9 000 – 9 500 рублей (~50-54 штуки проданных крабиков).
Во все остальные 27 дней месяца выручка — строгий ноль.
Почему живой товар с 1800 отзывами продается строго три раза в месяц пачками по 50 штук, а между ними пустота? В этот момент стало ясно: мы моделируем не поведение покупателей, а какую-то техническую неточность.
Глава 4. Битва с ветряными мельницами: Почему сломался математический аппарат
Мы обратились к математике. У нас была возможность обратиться к человеку с сильным математическим бэкграундом, и первой мыслью было: «Сейчас мы почистим данные нормальными статистическими фильтрами и все будет в масле».
Мы сели проверять гипотезы:
-
Распределение Стьюдента и
(трехсигмовые интервалы):
Мы пытались считать скользящее среднее и стандартное отклонение по продажам или остаткам и отрезать всё, что вылетает за доверительный интервал.
-
Почему развалилось: Данные продаж на маркетплейсах не имеют нормального распределения. Мы вообще в принципе не знаем, какое точно у нас распределение — оно сильно зависит от категории, а также от фильтров, которые мы выставим на набор данных. В ВУЗе мы обычно использовали статистику, имея некоторые допущения, гипотезы, предположения. От этого можно было оттолкнуться. А как определить в случае, когда мы не знаем распределение, верно ли мы применяем алгоритмы?
-
Всплеск продаж в день акции или после захода с рекламой может превышать среднее на 2–3 порядка. Если вы отсекаете по
или
, вы срезаете реальных лидеров рынка, но при этом пропускаете систематические выбросы у мелких товаров.
-
Проблема уровня агрегации (товар vs рынок):
Если проверять выбросы внутри одного товара, то у товара-пустышки дроп с 50 до 0 — это единственное событие, у него дисперсия равна нулю. Такой алгоритм не считает это выбросом.
А если проверять по всему рынку, то продажа 50 крабиков — обычное дело для крупного оптовика, но невозможная аномалия для селлера с нулевым рейтингом.
Переход к устойчивой (робастной) статистике: Log-IQR
Мы отказались от среднего и дисперсии в пользу медиан и квантильных размахов в логарифмическом пространстве.
Мы полагаем, что распределение цен и выручки мультипликативно, потому перевели метрики в логарифмическую шкалу:
Затем считали интерквартильный размах ():
Верхняя граница отсечения выбросов:
-
Для цен в rule-based сегментации мы взяли мягкий коэффициент, а для кластеризации на основе нейросетей — более строгий. Здесь не так важно значение коэффициента, так как оно подбирается экспериментально.
Создание централизованного фильтра: Revenue Quality Filter
Чтобы остановить поток фантомной выручки, мы спроектировали трехуровневый алгоритм верификации качества. Алгоритм не удаляет товар из выборки, но помечает его флагом артифакта и обнуляет расчетную выручку и продажи.
Математика трех правил:
-
Правило 1 (Глобальный экстремум):
Отсекает выбросы, когда товару приписывалась выручка в сотни миллиардов рублей.
-
Правило 2 (Аномальная выручка на один отзыв):
Для товаров из нижнего 5%-хвоста по отзывам () рассчитывается показатель удельной выручки:
Если превышает квантильный порог референсной группы рынка (товары с
):
товар помечается флагом артифакта.
-
Правило 3 (Фантомные новички):
Если у товара 0 отзывов (), а его выручка превышает 5 медианных выручек зрелых товаров в своем ценовом бине:
он признается артефактом.
Шок от реальных данных: десятки миллионов фантомных рублей
Когда мы прогнали этот фильтр на реальных выгрузках, результат все еще был далеко от идеала. Вот пример реального расчета:
Пример 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-е место рейтинга эффективности.
Мы применили формулу байесовского сглаживания с псевдонаблюдениями:
где:
-
— сумма метрики (выручки или отзывов) товаров, содержащих
-грамму
;
-
— реальное число вхождений фразы;
-
— глобальное среднее по всему рынку;
-
— статистический вес эмпирических данных.
|
Частота слова |
Доля фактического среднего |
Доля общерыночного среднего |
|
3 |
1.48% |
98.52% |
|
20 |
9.09% |
90.91% |
|
200 |
50.00% |
50.00% |
|
1000 |
83.33% |
16.67% |
Если слово встретилось 3 раза, его оценка на 98.5% определяется рыночным фоном, и лишь при сотнях повторений слово завоевывает право называться драйвером продаж.
Не думаю, что про Байесовское сглаживание стоит подробно рассказывать. Это достаточно популярная вещь — можно найти много информации в интернете. Мне например очень понравилась вот эта статья.
Внедрение внутреннего индекса доверия
Мы решили адаптировать этот принцип к выручке товаров. Вместо жесткого отсечения мы ввели внутренний весовой коэффициент доверия к выручке на основе отзывов:
где:
-
(минимальный вес доверия);
-
— количество отзывов карточки;
-
— 75-й перцентиль отзывов по рынку.
Внутренняя метрика использовалась для ранжирования карточек в выдаче, не позволяя товарам без валидации на основе данных группы пробиваться в топы.
Но оставался главный нерешенный вопрос: откуда всё-таки брались те загадочные пачки продаж по 44, 50, 53 штуки?
Глава 6. Момент истины: Секрет, который обнулил все расчеты по остаткам (как кэп остатков ломает аналитику)
Аналитика по дельте остатков системно дает сбой, поскольку интерфейс Wildberries кэпирует остатки в корзине, превращая колебания лимита в ложные продажи.
Конец июля 2026 года. Очередная ночная сессия дебага логов и поиска закономерностей.
Мы взяли один из тестовых аккаунтов селлера, загрузили на склад 100 единиц товара и открыли карточку в браузере как обычный покупатель. Нажали «Добавить в корзину» и попробовали выкрутить счетчик количества на максимум.
И тут наступил шок.
Wildberries кэпирует остатки на витрине!
Оказалось, что интерфейс корзины Wildberries не показывает реальный остаток товара на складе, если он превышает определенный лимит.
-
На витрине отдается искусственно обрезанное число.
-
Оно колеблется в диапазоне.
-
Более того, это значение может динамически меняться в зависимости от геолокации, типа склада, сессии пользователя или иных параметров.
Что это значило для нашего пайплайна?
Представьте:
-
У продавца на складе лежит 5 000 единиц товара.
-
Попытка узнать остатки:
qty = 54(сработал витринный кэп). -
На следующий день стучимся на витрину снова, но получаем другой лимит
qty = 44. -
Наш алгоритм делает расчет:
. Зафиксировано 10 продаж!
-
На третий день получаем
qty = 53. Алгоритм видит увеличение остаткасчитает это поставкой.
-
На четвертый день карточка на секунду выпала из выдачи:
qty = 0. Алгоритм радостно пишет: продано 53 штуки!
Мы неделями искали идеальные формулы математической статистики, чтобы победить шум, который не являлся шумом на самом деле.
Считать продажи вычитанием складских остатков на Wildberries — это попытка измерить глубину линейкой, длина которой произвольно меняется.
Глава 7. Архитектурный разворот: Как считать продажи, если остаткам верить нельзя
Осознав природу данных, мы совершили фундаментальный разворот в архитектуре.
Мы вернулись к отзывам, но не в их примитивном виде, а через иерархическую систему калибровки продаж продавца.
В чем суть нового подхода?
Есть не только данные по товарам, но и периодические снимки по продавцам в целом:
-
sold_products_count— общее число заказов / проданных товаров всего магазина селлера; -
product_feedbacks_count— суммарное число отзывов на всех товарах селлера.
За любой интервал времени для продавца известны два фундаментальных макро-показателя:
-
Сколько реально продал весь магазин:
.
-
Сколько реально новых отзывов получил весь магазин:
.
Это дает нам фактическую эмпирическую конверсию отзывов в заказы именно для этого продавца в этот конкретный календарный период:
При расчете выручки через отзывы есть тоже свои нюансы. Не должно быть никаких догадок из серии «на WB один отзыв приходится в среднем на 30–50 покупок». Такие догадки никуда не годятся. Для бренда дешевых носков этот коэффициент может быть равен 80, а для премиальной бытовой техники — 12.
Спуск на уровень товара
Когда у конкретного товара , принадлежащего данному продавцу, за интервал времени вырастает число отзывов на
, его доля в общем пуле продаж магазина определяется пропорцией прироста его отзывов к общему приросту отзывов селлера:
Целочисленное квантование: Метод Гамильтона
Поскольку получается дробным числом, а товар измеряется в целых штуках, мы применили классический метод распределения мест Гамильтона (метод наибольших остатков,
allocateinteger_sales):
-
Каждому товару с положительным приростом отзывов гарантированно отдается целая часть
(но не менее 1 шт).
-
Оставшийся нераспределенный остаток заказов поочередно раздается товарам с максимальной дробной частью.
Консервативная привязка цен
Чтобы исключить раздувание выручки, если продавец кратковременно менял цену (например, задрал перед акцией), мы сопоставляем интервал продажи с историей изменения цен:
Берется консервативный минимум цены за интервал наблюдения.
Результат архитектурного перехода
-
Исчезли фантомные миллионы: товары с 0 отзывов физически больше не могут получить ни единой продажи из-за скачков складских лимитов.
-
Ушел эффект кэпирования корзины: алгоритм вообще не смотрит на остаток товара, если тот подвержен витринным ограничениям.
-
Сохранилась адекватная динамика: если селлер запустил рекламу и пошли продажи с отзывами, они пропорционально и честно распределяются между его SKU.
Пример графика выручки товара-лидера в категории Зоотовары / Для собак / Ветаптека при расчетах выручки через отзывы.
Глава 8. Чек-лист по расчету аналитики маркетплейсов
Сравнительный анализ методов расчета продаж
|
Параметр сравнения |
Дельта остатков |
Отзывы |
|
Исходные данные |
Остатки на складах |
Отзывы на карточке и продавца |
|
Точность |
** |
***** |
|
Устойчивость к выбросам |
** |
**** |
|
Задержка данных |
24 часа |
несколько дней — несколько недель |
|
Применимость для анализа |
Аккуратно, требует хорошую фильтрацию данных |
Оптимален для оценок |
Чек-лист: Как построить надежный пайплайн e-commerce аналитики
Никогда не доверяйте исходным числам
Забудьте про стандартные распределения
Никаких . Используйте только непараметрические и робастные статистики: квантили (
), межквартильный размах (
), медианы и логарифмирование (
).
Внедряйте многоуровневую верификацию артефактов и выбросов
Если ваш алгоритм насчитал товару с 0 отзывов миллион рублей выручки — в 99.9% случаев неправ ваш алгоритм, а не покупатели смели склад.
Используйте алгоритмы по типу байесовского сглаживания, они реально работают
Редкие события должны притягиваться к среднему по рынку. Для текстовых признаков (нейминг, теги) и для метрик надежности используйте фиктивные псевдонаблюдения.
Связывайте микро-уровень с макро-уровнем:
Если метрика на микро-уровне дает сомнительный сигнал, проверяйте ее через родительскую сущность.
Заключение: Почему ни один внешний сервис не знает 100% правды
Если вам в рекламе очередного сервиса аналитики заявляют: «Мы знаем точные продажи каждого товара на Wildberries с точностью до одной копейки по нашим секретным данным» — теперь вы знаете, что эти секретные данные могут оказаться не очень верными.
Внешняя аналитика маркетплейсов — это не про точность до рубля, из открытых источников такое достать невозможно. Это про понимание структуры рынка, поиск реальных закономерностей и отсечение информационного мусора.
Когда мы перестали пытаться выжать из дырявых складских остатков несуществующую точность и построили математически выверенную модель, хоть и не дающую точность до рубля, система наконец начала выдавать отчеты, на которые можно опереться при принятии реальных бизнес-решений.
Внешняя аналитика — это всегда вероятностная модель и баланс компромиссов. Если вы сейчас проектируете свой пайплайн или хотите сопоставить данные своих категорий с нашими расчетами — базовый срез доступен в инструменте анализа рынка бесплатно и без необходимости привязывать карту.
А как вы боретесь с выбросами и аномалиями в данных? Делитесь в комментариях своим опытом — будет интересно обсудить!
ссылка на оригинал статьи https://habr.com/ru/articles/1086850/