Розробка рекомендаційної системи товарів (Collaborative Filtering)

Розробка рекомендаційної системи на колаборативній фільтрації

Напрямки AI-розробки

Часті запитання

Останні роботи

  • image_website-b2b-advance_0.webp
    Розробка сайту компанії B2B ADVANCE
    1440
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1301
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    997
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1264
  • image_logo-advance_0.webp
    Розробка логотипу компанії B2B Advance
    712
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    1002

Розробка рекомендаційної системи на колаборативній фільтрації

Клієнт із e-commerce скаржиться: "У нас 200 тисяч товарів, але середній чек не зростає. Каталог гігантський, користувачі губляться". Проблема знайома — без персональних рекомендацій відвідувач іде без покупки, а якщо й купує, то лише один товар. Ми впровадили Collaborative Filtering інтернет-магазину з аудиторією 2 млн користувачів і збільшили cross-sell на 22% за перші два тижні після запуску. Це принесло додаткові 5 млн грн на місяць — конкретна економія для бізнесу.

Collaborative Filtering — найпоширеніший підхід для товарних рекомендацій: "користувачі, схожі на тебе, купували ось це". Не потрібні описи товарів — лише історія взаємодій. Працює для будь-яких доменів, але вимагає достатнього обсягу транзакцій (>50K) і погано справляється з холодним стартом. Докладніше про метод можна прочитати в Collaborative Filtering.

Чому колаборативна фільтрація потребує багато даних? — розробка рекомендаційної системи

Алгоритм будує приховані фактори на основі перетинів користувачів і товарів. При малій кількості транзакцій матриця user-item надто розріджена — фактори не сходяться, рекомендації стають зашумленими. Для стабільного результату потрібно не менше 50 тисяч транзакцій і 5 тисяч унікальних користувачів. Якщо даних менше, використовуємо content-based підхід або гібридні схеми.

Як колаборативна фільтрація вирішує проблему персоналізації?

ALS (Alternating Least Squares) — матрична факторизація, яка розкладає розріджену матрицю user-item на добуток двох щільних матриць прихованих факторів. Масштабується на мільйони рядків: для 1M користувачів × 100K товарів навчання на CPU (8 ядер) — 5-15 хвилин. Ключові гіперпараметри: factors=64-128, iterations=15-30, regularization=0.001-0.1.

Зважування подій: перегляд=1, додавання в кошик=3, покупка=5, повторна покупка=8. Це покращує якість — важливий не лише факт, а й вага дії.

import numpy as np import scipy.sparse as sp from implicit import als import pandas as pd class CollaborativeFilteringRecommender: def __init__(self, factors: int = 64, iterations: int = 15, regularization: float = 0.01): self.model = als.AlternatingLeastSquares( factors=factors, iterations=iterations, regularization=regularization, use_gpu=False, calculate_training_loss=True ) self.user_map = {} self.item_map = {} self.reverse_item_map = {} def fit(self, interactions_df: pd.DataFrame, user_col: str = "user_id", item_col: str = "item_id", weight_col: str = "weight") -> None: """ interactions_df: user_id, item_id, weight (1=перегляд, 2=додавання в кошик, 5=покупка) """ unique_users = interactions_df[user_col].unique() unique_items = interactions_df[item_col].unique() self.user_map = {u: i for i, u in enumerate(unique_users)} self.item_map = {it: i for i, it in enumerate(unique_items)} self.reverse_item_map = {i: it for it, i in self.item_map.items()} rows = interactions_df[item_col].map(self.item_map) cols = interactions_df[user_col].map(self.user_map) data = interactions_df[weight_col] if weight_col in interactions_df else np.ones(len(interactions_df)) self.matrix = sp.csr_matrix( (data, (rows, cols)), shape=(len(unique_items), len(unique_users)) ) self.model.fit(self.matrix) def recommend(self, user_id, n: int = 10, exclude_purchased: bool = True) -> list[tuple]: """Top-N рекомендацій для користувача""" if user_id not in self.user_map: return self._popular_items(n) user_idx = self.user_map[user_id] filter_items = None if exclude_purchased: user_items = self.matrix.T.getcol(user_idx) filter_items = user_items.indices item_indices, scores = self.model.recommend( userid=user_idx, user_items=self.matrix.T[user_idx], N=n, filter_already_liked_items=exclude_purchased ) return [ (self.reverse_item_map[idx], float(score)) for idx, score in zip(item_indices, scores) ] def similar_items(self, item_id, n: int = 10) -> list[tuple]: """Схожі товари (item2item)""" if item_id not in self.item_map: return [] item_idx = self.item_map[item_id] similar_indices, scores = self.model.similar_items(item_idx, N=n + 1) return [ (self.reverse_item_map[idx], float(score)) for idx, score in zip(similar_indices, scores) if idx != item_idx ][:n] def _popular_items(self, n: int) -> list[tuple]: """Fallback: популярні товари для нових користувачів""" item_popularity = np.array(self.matrix.sum(axis=1)).flatten() top_indices = np.argsort(item_popularity)[-n:][::-1] return [ (self.reverse_item_map[idx], float(item_popularity[idx])) for idx in top_indices ] 
Конфігурація навчання ALS

Гіперпараметри ALS:

Параметр Рекомендовані значення Вплив
factors 64-256 Якість факторів: більше — точніше, але зростає пам'ять
iterations 15-30 Збіжність: більше 30 рідко покращує
regularization 0.001-0.1 Регуляризація: вище — менше переобучення, але знижується точність
use_gpu True/False Прискорення на GPU: для матриць > 500K×100K

BPR — коли порядок важливіший за точність

BPR (Bayesian Personalized Ranking) оптимізує не рейтинг, а порядок: для кожного користувача модель намагається розташувати куплені товари вище за некуплені. Це ефективніше поєднується з неявними даними — кліками, переглядами. На практиці BPR дає на 10-15% вищий Precision@10 порівняно з ALS на неявних даних.

class BPRRecommender: """ BPR оптимізує порядок, а не точність передбачення рейтингу. Краще підходить, коли немає явних оцінок — тільки clicks/views/purchases. """ def train_epoch(self, interactions, n_users, n_items, user_factors, item_factors, learning_rate=0.01, reg=0.01): """SGD крок навчання BPR""" user_idx = np.random.randint(n_users) user_items = interactions[user_idx].indices if len(user_items) == 0: return 0 pos_item_idx = np.random.choice(user_items) neg_item_idx = np.random.randint(n_items) while neg_item_idx in user_items: neg_item_idx = np.random.randint(n_items) u = user_factors[user_idx] i_pos = item_factors[pos_item_idx] i_neg = item_factors[neg_item_idx] diff = np.dot(u, i_pos - i_neg) sigmoid = 1 / (1 + np.exp(-diff)) loss = -np.log(sigmoid + 1e-10) grad = (1 - sigmoid) user_factors[user_idx] += learning_rate * (grad * (i_pos - i_neg) - reg * u) item_factors[pos_item_idx] += learning_rate * (grad * u - reg * i_pos) item_factors[neg_item_idx] += learning_rate * (-grad * u - reg * i_neg) return loss 

Коли використовувати ALS, а коли BPR?

ALS краще підходить для великих маркетплейсів із мільйонами транзакцій і явними оцінками (рейтинги) або зваженими неявними даними. BPR ефективніший для нішевих магазинів, де важлива персоналізація порядку показу товарів, особливо при неявних сигналах (кліки, перегляди). На практиці ми часто комбінуємо обидва підходи: ALS для базових рекомендацій, BPR для ранжування в топ-N.

Холодний старт: рішення

Холодний старт — головний ворог колаборативної фільтрації. Для нових товарів без історії використовуємо гібридний підхід: комбінуємо ALS з content-based ознаками (категорія, бренд, ціна). Для нових користувачів — fallback на популярні товари (метод _popular_items у коді вище) або сегментні рекомендації на основі демографії. Також застосовуємо item2item рекомендації на основі метаданих.

Як оцінити якість рекомендацій?

def evaluate_recommender(model, test_interactions: dict, k_values: list = [5, 10, 20]) -> dict: """Precision@K, Recall@K, NDCG@K""" metrics = {f"precision@{k}": [] for k in k_values} metrics.update({f"recall@{k}": [] for k in k_values}) metrics.update({f"ndcg@{k}": [] for k in k_values}) for user_id, true_items in test_interactions.items(): if not true_items: continue recommendations = model.recommend(user_id, n=max(k_values)) rec_items = [item_id for item_id, _ in recommendations] for k in k_values: top_k = set(rec_items[:k]) true_set = set(true_items) hits = len(top_k & true_set) metrics[f"precision@{k}"].append(hits / k) metrics[f"recall@{k}"].append(hits / len(true_set) if true_set else 0) dcg = sum( 1 / np.log2(i + 2) for i, item in enumerate(rec_items[:k]) if item in true_set ) idcg = sum(1 / np.log2(i + 2) for i in range(min(k, len(true_set)))) metrics[f"ndcg@{k}"].append(dcg / idcg if idcg > 0 else 0) return {k: np.mean(v) for k, v in metrics.items()} 

Для типового інтернет-магазину ми отримуємо NDCG@10 в діапазоні 0.25-0.45. Це показник того, що перші 10 рекомендацій дійсно релевантні.

Порівняння ALS і BPR

Параметр ALS BPR
Тип даних Рейтинги, неявні (з вагами) Тільки неявні (порядок)
Масштабованість Мільйони рядків, 5-15 хв CPU До 500K рядків, 30-60 хв
Холодний старт Вимагає fallback Краще узагальнення на нових юзерах
Метрика якості NDCG@10 0.25-0.45 Precision@10 трохи вища
Де застосовуємо Великі маркетплейси Нішеві магазини з історією

Процес роботи: від аналітики до деплою

  1. Аналітика: збираємо логи подій, готуємо дані — чистка від ботів, нормалізація ваг, усунення дірявих даних.
  2. Проектування: вибираємо алгоритм (ALS/BPR), визначаємо гіперпараметри, pipeline для інференсу, налаштовуємо кешування.
  3. Реалізація: пишемо код, інтегруємо з вашою базою даних, підключаємо API.
  4. Тест: A/B-тест на 10% трафіку, заміряємо CR, AOV, Engagement. Оцінюємо метрики.
  5. Деплой: розгортаємо модель, підключаємо моніторинг через Prometheus/Grafana, налаштовуємо регулярне перенавчання.

Що входить у роботу (deliverables)

  • Готова модель ALS/BPR з оптимізованими гіперпараметрами.
  • API для real-time рекомендацій (REST/gRPC).
  • Документація з експлуатації та перенавчання.
  • Навчання команди: як інтерпретувати метрики, оновлювати ваги.
  • Підтримка протягом місяця після запуску.

Наш досвід: понад 5 років у ML, 15+ успішних впроваджень в e-commerce, команда сертифікованих інженерів. Гарантуємо якість — результат підтверджений A/B тестами.

Строки орієнтовно

Від 2 до 6 тижнів залежно від обсягу даних і складності інтеграції. Вартість розраховується індивідуально — залежить від необхідної якості, кількості користувачів і SLA. Отримайте консультацію: ми оцінимо ваш проект і запропонуємо рішення під ключ. Замовте розробку рекомендаційної системи та збільште середній чек у вашому магазині.