Реализация рекомендательной системы для маркетплейса
Рекомендательная система маркетплейса решает задачу сложнее, чем в обычном e-commerce: нужно балансировать интересы покупателя (релевантность), продавца (продвижение товаров) и платформы (монетизация). Дополнительные сложности: миллионы SKU, тысячи продавцов, высокая конкуренция за одни и те же запросы.
Многоцелевая рекомендательная архитектура
import numpy as np
import pandas as pd
from dataclasses import dataclass
@dataclass
class MarketplaceItem:
item_id: str
seller_id: str
price: float
rating: float
review_count: int
is_promoted: bool
conversion_rate: float
inventory: int
class MarketplaceRecommender:
"""Рекомендации с балансировкой нескольких целей"""
def __init__(self, user_model, item_index, seller_index):
self.user_model = user_model
self.item_index = item_index
self.seller_index = seller_index
# Веса целевых функций
self.weights = {
'relevance': 0.50, # Релевантность для пользователя
'quality': 0.20, # Рейтинг и отзывы
'seller_diversity': 0.15, # Разнообразие продавцов
'promoted': 0.10, # Продвинутые товары
'conversion': 0.05 # Исторический CR
}
def recommend(self, user_id: str, context: dict,
n: int = 20) -> list[dict]:
"""Многоцелевые рекомендации"""
# Retrieval: топ-кандидаты по релевантности
user_emb = self.user_model.get_user_embedding(user_id)
candidates = self.item_index.search(user_emb, k=200)
# Scoring: многоцелевая функция
scored = []
seller_count = {}
for item_id, relevance_score in candidates:
item = self._get_item(item_id)
if item is None or item.inventory == 0:
continue
# Качество товара
quality_score = (
item.rating / 5.0 * 0.6 +
np.log1p(item.review_count) / 10 * 0.4
)
# Штраф за концентрацию продавцов
seller_count[item.seller_id] = seller_count.get(item.seller_id, 0) + 1
seller_diversity = 1 / seller_count[item.seller_id]
# Promoted boost (с ограничением)
promo_boost = 1.2 if item.is_promoted else 1.0
# Финальный скор
final_score = (
self.weights['relevance'] * relevance_score +
self.weights['quality'] * quality_score +
self.weights['seller_diversity'] * seller_diversity +
self.weights['promoted'] * (promo_boost - 1) +
self.weights['conversion'] * item.conversion_rate
)
scored.append({
'item_id': item_id,
'seller_id': item.seller_id,
'score': final_score,
'relevance': relevance_score,
'quality': quality_score
})
# Сортировка и возврат
scored.sort(key=lambda x: x['score'], reverse=True)
return scored[:n]
def _get_item(self, item_id: str) -> MarketplaceItem:
return self.seller_index.get(item_id)
def similar_items_cross_seller(self, item_id: str,
n: int = 6) -> list[dict]:
"""Похожие товары от других продавцов (comparison shopping)"""
item = self._get_item(item_id)
if not item:
return []
similar = self.item_index.search_similar(item_id, k=20)
# Фильтрация: другой продавец, но похожий товар
cross_seller = [
s for s in similar
if self._get_item(s[0]) and self._get_item(s[0]).seller_id != item.seller_id
]
return cross_seller[:n]
Холодный старт для новых товаров
def handle_new_item_cold_start(self, item: MarketplaceItem,
item_features: dict) -> float:
"""Начальный буст для новых товаров"""
base_score = 0.3 # Базовая позиция
# Буст на основе метаданных
if item.rating >= 4.5 and item.review_count >= 10:
base_score += 0.2
if item.price < self._get_category_avg_price(item_features.get('category')):
base_score += 0.1 # Конкурентная цена
# Explore-exploit баланс для новых товаров
# Показываем 5-10% трафика для сбора данных
import random
if random.random() < 0.08: # 8% exploration
return 0.7 + random.random() * 0.3
return base_score
Маркетплейс-специфичные метрики: GMV per session (главная), seller satisfaction score (NPS продавцов), category diversity (разнообразие категорий в рекомендациях), promoted/organic ratio (отношение рекламных к органическим). Типичные результаты: GMV uplift от рекомендаций 12-20%, CTR главной страницы +30-50%.







