ООО «ПРОСЕПТ» — российская производственная компания, специализирующаяся на выпуске профессиональной химии. В своей работе используют опыт ведущих мировых производителей и сырье крупнейших химических концернов. Производство и логистический центр расположены в непосредственной близости от Санкт-Петербурга, откуда продукция компании поставляется во все регионы России. Сайт: https://prosept.ru/
Введение в задачу:
Заказчик производит несколько сотен различных товаров бытовой и промышленной химии, а затем продаёт эти товары через дилеров. Дилеры, в свою очередь, занимаются розничной продажей товаров в крупных сетях магазинов и на онлайн площадках.
Для оценки ситуации, управления ценами и бизнесом в целом, заказчик периодически собирает информацию о том, как дилеры продают их товар. Для этого они парсят сайты дилеров, а затем сопоставляют товары и цены. Зачастую описание товаров на сайтах дилеров отличаются от того описания, что даёт заказчик. Например, могут добавляться новый слова (“универсальный”, “эффективный”), объём (0.6 л -> 600 мл). Поэтому сопоставление товаров дилеров с товарами производителя делается вручную. Цель этого проекта - разработка решения, которое отчасти автоматизирует процесс сопоставления товаров. Основная идея - предлагать несколько товаров заказчика, которые с наибольшей вероятностью соответствуют размечаемому товару дилера. Предлагается реализовать это решение, как онлайн сервис, открываемый в веб- браузере. Выбор наиболее вероятных подсказок делается методами машинного обучения.
Документация к предоставленным данным:
Заказчик предоставил несколько таблиц (дамп БД), содержащих необходимые данные:
1 marketing_dealer - список дилеров;
2 marketing_dealerprice - результат работы парсера площадок дилеров:
-
product_key - уникальный номер позиции;
-
price - цена;
-
product_url - адрес страницы, откуда собраны данные;
-
product_name - заголовок продаваемого товара;
-
date - дата получения информации;
-
dealer_id - идентификатор дилера (внешний ключ к marketing_dealer)
3 marketing_product - список товаров, которые производит и распространяет заказчик;
-
article - артикул товара;
-
ean_13 - код товара (см. EAN 13)
-
name - название товара;
-
cost - стоимость;
-
min_recommended_price - рекомендованная минимальная цена;
-
recommended_price - рекомендованная цена;
-
category_id - категория товара;
-
ozon_name - названиет товара на Озоне;
-
name_1c - название товара в 1C;
-
wb_name - название товара на Wildberries;
-
ozon_article - описание для Озон;
-
wb_article - артикул для Wildberries;
-
ym_article - артикул для Яндекс.Маркета;
4 marketing_productdealerkey - таблица матчинга товаров заказчика и товаров дилеров
-
key - внешний ключ к marketing_dealerprice
-
product_id - внешний ключ к marketing_product
-
dealer_id - внешний ключ к marketing_dealer
До дедлайна 19:00 29 ноября
-
Команда знакомится с предоставленными данными.
-
Формулируется DS задача, утверждается единые схема валидации решений и метрика качества.
-
Выбирается основной способ решения задачи (модель первого этапа с функционалом финального решения), который будет представлен к дедлайну 29 ноября:
- Рассматриваются и валидируются разные способы предобработки входных данных модели.
- Рассматриваются и валидируются разные ml движки решения.
-
Подготовка модели первого этапа к сдаче на ревью в том виде, в котором ею сможет пользоваться BackEnd департамент команды.
-
Подготовка репозитория решения с jupyter notebook, содержащим основные вехи разработки модели первого этапа.
После дедлайна DS до единого дедлайна
-
Генерация новых фичей, улучшение схемы предобработки входных данных.
-
Построение и валидация модели второго этапа (реранжирующий классификатор).
-
Тюнинг реранжирующего классификатора.
-
Предоставление финального решения BackEnd команде, помощь в его инициализации.
10. Оформление документации и ожидание результатов хакатона.
Роль алгоритма в функционале приложения
Наш алгоритм должен помочь разметчику сопоставить товар диллера с одним из нескольких сотен товаров фирмы заказчика. Важно отметить, что финальное решение принимает именно разметчик. Так вот, насколько видит наша команда, алгоритм для каждого из предложенных товаров диллеров должен вернуть ранжированный список всех товаров заказчика так, чтобы релевантный айтем оказался максимально высоко в топе. Таким образом перед нами тривиальная задача ранжирования.
- Для товара диллера у заказчика есть только один релевантный айтем.
- Основными признаками для матчинга выступают нейминги товаров.
- Товары диллеров всегда новые, а множество товаров заказчика меняется редко.
В качестве метрики качества мы утвердили Среднеобратный ранг (Mean Reciprocal Rank):
Т.к. соответствия товаров диллеров товарам заказчика не изменяются со временем, обычная кросс-валидация идеально нам подходит. Будем валидироваться на 5 фолдах, в тестовой выборке каждого фолда будет примерно 300-400 соответствий.
Первый этап: Как ранее указывалось, основным признаком для сопоставления являются нейминги товаров. Таким образом в качестве модели первого этапа мы представим функцию, помещающую все нейминги товаров заказчика в единое векторное пространство с помощью текстового векторизатора. Для формирования списка рекомендаций нейминг товара дилера помещается в то же пространство, а затем товары заказчика ранжируются по косинусной близости. В итоге уже обученная модель будет принимать массив с неймингами товаров дилера, а возвращать двумерный массив с рекомендациями.
Лучший MRR показала модель, ранжирующая по косинусному сходству эмбеддинги xlm-roberta-large модели, предобученной командой intfloat (https://huggingface.co/intfloat/multilingual-e5-large). На кросс-валидации модель демонстрирует 0.856 MRR@10. Это означает, что средний ранг релевантного айтема в списке рекомендаций модели приблизительно равен 1.17 (чаще всего на первом месте, редко на втором, редко-редко на других). Таким образом разметчик сможет практически моментально находить релевантный айтем заказчика.
from main import *
model = DistanceRecommender(
vectorizer=InfloatVectorizer(),
simularity_func=cosine_similarity,
text_prep_func=string_filter_emb
)
model.from_pretrained()
names = ['Герметик акриловый цвет белый , ф/п 600 мл. (12 штук )',
'Гель эконом-класса для мытья посуды вручную. С ароматом яблокаCooky Apple Eконцентрированное средство / 5 л ПЭТ',
'Средство для удаления ржавчины и минеральных отложений щадящего действияBath Acid концентрат 1:200-1:500 / 0,75 л ',
'Антисептик многофункциональный ФБС, ГОСТ / 5 л',
'Гелеобразное средство усиленного действия для удаления ржавчины и минеральных отложенийBath Extraконцентрат 1:10-1:100 / 0,75 л']
print(model.recommend(names))
С моделью можно взаимодействовать с помощью API реализованного на FastApi.
- Необходимо запустить сервер uvicorn локально. \n Так же необходимо выставить порт, если запускать проект вместе с backend'ом локально --port 8001
uvicorn api.main:app
API имеет один эндпоинт - '/machine-matching/' и принимает POST-запрос с телом запроса:
{
"name_dealer_product": "наименование продукта дилера"
}
И отдаёт ранжированный список id's товаров заказчика:
[446 464 466 ... 115 482 436]
python:3.10
pandas==2.1.3
transformers==4.35.2
torch==2.1.1
scikit-learn==1.3.2