ML for Value / Ваня Максимов – Telegram
ML for Value / Ваня Максимов
5.59K subscribers
191 photos
1 video
1 file
119 links
Путь от ML-модели до Value для компании | RecSys, Search, LLM, Pricing и CLTV

Ваня Максимов, @Ivan_maksimov
Head of AI | Recsys, search, llm @Y.Market, ex-WB, ex-Delivery Club

Консультирую компании, Веду курсы
Публикую релевантную рекламу
Download Telegram
Как вам блок про "ML - это не только модели"?
Оптимизация промо акций
Часть 4
Как померить бизнес-эффект? 💰💰

- Очевидно, А/В тестом!
- Да, но не все так просто. Опять мои любимые implementation details:)


Грабли #1: Выбор корректного теста

Классические А/В из учебников применяются не так часто, т.к. столкновение теории с реальностью разбивает первую вдребезги

Что же не так с А/В из учебника? Вспомним, что там пишут:

Шаг 1. Разбиваем юзеров на А и В группы.. Но стоп. Мы же делаем акции на товары в магазине, как же мы побьем юзеров? Правильно - никак. Нужно сплитить магазины

Шаг 2. Провести А/А тест. Обычно в лекциях это упоминается вскользь. Предполагают, что А/А тест всегда успешен. Но в кейсе со сплитом по магазинам зачастую это не так 🙅‍♀ Хьюстон, у нас проблемы

Причин может быть 2:
>> Магазинов мало (даже у Х5 и Магнита их ~20к по всей России) + А/В на полстраны вам запустить никто не даст. В итоге, дай бог, дадут 1-2к магазинов для теста
>> Магазины очень сильно отличаются (разные города, районы города, уровень зп,...)

Что же делать?
1. Можно стратифицированно сэмплировать магазины для А и В групп. Не рекомендую, т к очень сложно подобрать хорошие фичи, по которым вы будете стратифицировать (город? з/п? Население? Все сразу?)

2. Switch back тесты. Рекомендую.
Хорошая статья от DoorDash на эту тему:
https://www.google.com/amp/s/doordash.engineering/2019/02/20/experiment-rigor-for-switchback-experiment-analysis/amp/

TL;DR;
Раз в неделю (в идеале день, но у нас оффлайн ритейл) вы делаете сплитование заново. Если тест идёт 3 недели, то один и тот же магазин может на одной неделе быть в А группе, а на другой - в В. Это позволяет нивелировать различия между средними в А и В группах, и даже снизить дисперсию метрик (ускорить тест)

Вывод
Внимательно следите за тем, какую технику А/В вы используете

#pricing #timeseries
👌1
Грабли #2: А/В тест длиною в жизнь

Допустим, мы выбрали относительно хороший дизайн А/В:
-- Метрика - прибыль на 1 магазин за 1 день
-- Switch back тест
-- Нам разрешили взять максимум 2к магазинов в тестовую группу

Всё, запускаем? Вообще, нужно бы посчитать, сколько недель нам нужно держать А/В. Считаем и получаем.. 2 года 😱

И тут мы приходим к необходимости ускорить А/В тест. Ускорить А/В = снизить дисперсию вашей метрики. Я оставлю ссылки на варианты решения этой проблемы и напишу TL; DR
Когда ждёшь, пока прокрасится метрика в А/В, а не ускоряешь его
Ускорение А/В
Способ 1. Стратификация и CUPED
https://youtu.be/pZpUM08mv-E

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

Тогда итоговое среднее останется таким же как и в классическом подходе, а дисперсия упадёт - - > тест нужно будет держать меньше

CUPED
В видео объяснение довольно сложное, но по сути вы просто строите линейную регрессию вашей целевой метрики на фичи

Важно (!): значение фичей должно быть известно ДО начала эксперимента

Пример фичей:
-- Целевая метрика магазина N недель назад
-- Город, в котором находится магазин
--...

Потом, вы из целевой метрики вычитание её прогноз. И считаете А/В на уже получившейся величине. Это сильно ускоряет тест, но снижает его интерпретируемость

P.S. Для любителей строгой мат.статистики - выше я описал лишь концепцию. Если вдаваться в детали, то текст выше в чем-то не совсем корректен. Но суть идеи передаёт отлично:)
1
Будьте осторожны с интерпретацией CUPED (под его капотом линейная регрессия)
Ускорение А/В
Способ 2. Выбрать другую метрику 😅

Да-да, вы не ослышались. Можно и иногда даже нужно выбирать другие метрики в А/В, чтобы ждать результатов не 2 года, а 2-3 недели

Прибыль = кол-во заказов * средняя прибыль с одного заказа

Невероятно, но факт (ну, почти всегда факт 😜): дисперсия этих множителей сильно меньше дисперсии прибыли

А значит, А/В успешен, если
хотя бы одна из метрик растёт, а другая - не падает

P.S. Но не забывайте про поправки (например, Бонферонни) для множественного тестирования гипотез
Ускорение А/В
Способ 3: Байесовская статистика
https://youtu.be/Wxw1lseUXVU
(про Байеса - в конце видео)

Одно из немногих успешних применений байеса - А/В тесты и многорукие бандиты

Тут TL;DR не получится, так как много теории. Если интересно, то лучше прочитайте об этом в годных статьях:

Байесовские А/В:
https://link.medium.com/9b4ukKvHK9

Байесовские многорукие бандиты:
https://lilianweng.github.io/lil-log/2018/01/23/the-multi-armed-bandit-problem-and-its-solutions.html
Как вам посты про дизайн и ускорение А/В?

P.S. А ещё: стратификация, линеаризация, байес и т д - просто частные случаи CUPED
Грабли универсальные: Тесты ds-кода

Сразу оговорюсь, что я ни разу не ML Engineer / Devops. Бакалавриат я закончил вообще по мат.методам в экономике. И до начала работы почти ничего не слышал о юнит- и других тестах

Но как только мои модели начали использоваться, даже мне стало очевидно, что без тестов - никуда. Без них пайплайны падают, их починка отнимает кучу времени, а бизнес-заказчики недоумевают где их 300кк/сек от внедрения ML

А если ваши пайплайны падают слишком часто - не за горами тот момент, когда и вы будете недоумевать про свои 300кк/сек 🙂

Так что начнем мое небольшое введение в тестирование ML-пайплайнов!

ML-тесты очень специфичны. В продакшене каждый день мы обучаемся на немного разных данных. При этом даже на одних и тех же inputs можно получать разные outputs. Мы в общем случае не знаем, какой должен быть ответ на одном или другом примере

Поэтому я предлагаю покрывать отдельными тестами:
— входные данные (да-да, и для нейронок тоже)
— каждый этап трансформации данных
— predict

В моем идеальном мире, код может выглядеть примерно так:

df = read_data()
test_on_inputs(df)

df = first_transform(df)
test_on_transform(type='first')

df = second_transform(df)
test_on_transform(type='second')

model = MyFavoriteModel()
model.fit(df)
test_on_predict(model, df)


Далее опишу тесты, которые я использую каждый день стараюсь использовать. А чтобы убедить вас, что тесты нужны, добавлю мои самые эпичные фейлы
На мой взгляд 90% ошибок - в самых элементарных вещах. Перепутали типы данных, сделали left join вместо inner и т.п. И если вы думаете, что это происходит "с любым, но точно не со мной" - скорее всего вы заблуждаетесь:) Для таких кейсов представляю вам:

Капитанский набор тестов для DS
.. и мои эпичнейшие фейлы:

1. Проверка типов входных данных
Прочитать pandas dataframe без указания типов данных и получить out of memory error - это уже стало классикой

2. Проверка кол-во строк в датафрейме
Вы обучили модель и она показала 99% AUC? Запускаете регулярный джоб на обучение и вдруг видите совершенно неадекватные предсказания и AUC около 50%? Поздравляю, еще одна классика: джоб автоматически обучил вашу SOTA модель на не собранной до конца базе (например, там оказалось 10к строк вместо 10кк)

3. Проверяйте долю NaN-ов и уникальных значений в каждом столбце
Я однажды сджойнил датафрейм с поминутными событиями и датафрейм "дата-праздник". Угадайте, для каких минут были не NaN-ы (для ХХ-ХХ-ХХ:00:00). Поэтому мои юзеры праздновали не только НГ исключительно 1 минуту в полночь, но и все остальные праздники

4. Проверяйте распределение фичей
- min/max значения (особенно актуально для дат)
- Среднее

Я встречал отрицательные цены, возраст в 5000+ лет, отрицательный прогноз продаж (хотя в трейне только положительные продажи, но бустингу все равно), даты после сегодняшнего дня в трейне и еще много артефактов. И да, замечаете вы их далеко не сразу. В свою защиту скажу, что и появляются такие артефакты тоже не всегда сразу

5. Тесты на логику
- Статистики по категориям (условно через df.groupby(store_id)['item_id'].nunique() посчитать, что в каждом магазине > 1000 товаров
- Продажи любого товара не больше 10к шт в день

Если в ваш магазин заехал оптовик и закупил 5 Камазов картошки по акции, то это легко сломает вам все модели

6. Тесты на логику predict
Вы же ожидаете, что прогноз продаж вырастет, если увеличить скидку на товар? Так напишите на это тест

Кстати, почти все эти тесты можно очень удобно закодить с помощью достаточно новой либы great-expectations:
https://docs.greatexpectations.io/en/latest/
*На самом деле тесты вам помогут найти баги в пайплайне и даже улучшить качество модели!

Но это не точно
Все то, что я описал выше, касается картинок и текстов тоже

Нет ничего более обидного, чем когда обучил Sota сетку с огромным входным размером изображения, а на вход в проде подаёшь микро картинку (условно, 256х256) и автоматически pad-ишь ее нулями.. Всё работает, но качество - так себе
Вам понравился пост про ML-тесты?

Если интересно услышать еще больше true sad stories про фейлы из-за отсутствия тестов (или рассказать свою историю) - добро пожаловать в комментарии
Рекомендательные системы
Всё, чему нас учили - неправда

Следующая серия постов будет посвящена получению Business Value от рекомендательных систем (RecSys). А пока поделюсь с вами довольно значимым научным открытием в 2020 году:

Оказалось, что некорректно использовать наши любимые NDCG, precision@k, recall@k для сравнения моделей, если эти метрики посчитаны на сэмпле данных. Вместо этого корректно использовать AUC@k 😱

А сэмплирование используется почти во всех продакшн-системах, так как товаров сотни тысяч, а то и миллионы (метрики считают обычно на сэмпле из 100-1000 товаров)

Видео с KDD-2020 на эту тему (всего 15 мин)


Для тех, кто не очень близок к сфере recsys: в 99% курсах на первом же уроке говорят, что использовать AUC для оценки качества ранжирования нельзя, т.к он плохо учитывает порядок рекомендаций

На очень годных курсах добавляют, что AUC@k чуть получше, но тоже не айс 🥶

И настоятельно советуют использовать те самые NDCG, precision@k, ...

Вот так и переворачиваются в момент все представления о задаче ранжирования

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

#recsys
Рекомендательные системы
Часть 1
А зачем?

Новая серия постов будет посвещена классике - рекомендательныем системам в ритейле. На этот раз представьте себя на месте data scientist, который работает в крупной сети бытовой техники / мебели (IKEA, М.Видео, Hoff)

К вам приходит менеджер и предлагает сделать персональную e-mail рассылку с товарами. Но прежде чем радоваться новой челленджевой задаче, задайте ему вопрос "А зачем?"

Многие очень стесняются его задавать, думая, что выглядят глупо. Но поверьте, подавляющее большинство людей (разработчики, менеджеры, да чего уж мелочиться: data scientist-ы тоже) не знают хотя бы +/- точного ответа на этот вопрос

#recsys
Представим, что на вопрос нашего воображаемого ds менеджер ответил "Чтобы повысить продажи". Вы уже знаете, что под продажами можно понимать все что угодно

И вроде бы в голове есть картинка:
1. Рекомендуем вот этот шкаф
2. Юзеру нравится рекомендация
3. Юзер приезжает к нам (заходит в интернет-магазин) и покупает его

Но опытные DS сразу увидят подвох:
>> В нашем магазине у клиентов довольно мало покупок (вы часто покупаете холодильник или шкаф?)
>> Очень сложно угадать конкретный предмет для рекомендаций

В общем, стандартный кейс для холодного старта

Поэтому, скорее всего, вы просто не сможете нормально обучить рекомендательную систему. Что же делать?
Ну и какой конкретно шкаф вы порекомендуете юзеру, по которому нет / почти нет данных?
Давайте ещё раз зададим вопрос "А зачем? ", внимательно смотря на нашу схему:

1. Рекомендуем вот этот шкаф
2. Юзеру нравится рекомендация
3. Юзер приезжает к нам (заходит в интернет-магазин) и покупает его

Начнём с конца (3): "юзер .. покупает его". Нам точно нужно именно это? А если юзер купит не тот шкаф, что мы рекомендовали, а другой? Другой шкаф = тоже успех! Значит, нам нужно, чтобы юзер купил хоть что-то

Если нужно, чтобы он купил хоть что-то, но рекомендации хотим все ещё персональные, то мы можем рекомендовать не товар, а категорию товаров

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

И вот, наша рекомендация "шкаф такой-то", где мы очень вряд ли сможем угадать предпочтение пользователя, превратилась в "Скидка на шкафы 10%". Уже лучше, не правда ли? И нашу итоговую цель мы точно также достигаем

И получаем схему :
1. Рекомендуем вот этот шкаф категорию и скидку на нее
2. Юзеру нравится рекомендация
3. Юзер приезжает к нам (заходит в интернет-магазин) и покупает его хоть что-то

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