Розробка AI-системи корзинного аналізу Market Basket Analysis

Проектуємо та впроваджуємо системи штучного інтелекту: від прототипу до production-ready рішення. Наша команда поєднує експертизу в машинному навчанні, дата-інжинірингу та MLOps, щоб AI працював не в лабораторії, а в реальному бізнесі.
Показано 1 з 1Усі 1564 послуг
Розробка AI-системи корзинного аналізу Market Basket Analysis
Середній
~3-5 днів
Часті запитання

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

Етапи розробки AI-рішення

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

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

Розробка AI-системи корзинного аналізу Market Basket Analysis

Роздрібна мережа з 500 магазинів втрачала 12% виручки через відсутність персоналізованих рекомендацій. Товари в кошику не перетиналися, промо-акції не використовували синергію, а відділ аналітики витрачав тижні на Excel-звіти. Ми побудували AI-систему корзинного аналізу, яка замінила ручну працю та збільшила крос-продажі на 18% за перший квартал. Ключова ідея — гібрид класичних association rules та нейромереж, що дає інтерпретованість основних правил і глибину long-tail.

ML-рішення в рітейлі стають стандартом. Сегментація кошиків за типом покупця — ще один шар персоналізації, який ми реалізуємо через кластеризацію транзакцій.

Які проблеми вирішує Market Basket Analysis?

Розрідженість даних. У типовому датасеті 1 млн транзакцій і 10 тис. SKU більшість пар товарів зустрічаються рідко. Класичні алгоритми (Apriori, FP-Growth) дають багато шуму. Нейромережева модель вловлює слабкі сигнали, використовуючи ембеддінги та механізм self-attention. Додатково застосовуємо техніки аугментації даних і зваженого семплювання для long-tail категорій.

Сезонні тренди. Правила, виведені на даних січня, не працюють у липні. Окремі моделі для кожного сезону підвищують точність на 30%. Враховуємо свята, розпродажі та погодні фактори. Для кожного сезону будуємо свої правила та ембеддінги, що дозволяє рекомендувати сезонні товарні зв'язки.

Масштабування. Обробка 1 млн транзакцій FP-Growth на single CPU займає 3-8 хвилин. Для щоденного перерахунку в реальному часі використовуємо інкрементальні оновлення та GPU для нейромережі. Гібридна архітектура дозволяє перераховувати правила раз на день, а нейромережу донавчати раз на тиждень — це баланс між швидкістю та якістю.

Брудні дані — ще одна проблема. Пропуски, дублікати та застарілі ціни безпосередньо впливають на якість правил. Ми автоматизуємо ETL-процеси з перевіркою узгодженості.

Чому гібридний підхід кращий за класичні правила?

Згідно з звітом McKinsey, рітейлери з AI-рекомендаціями збільшують виручку на 10–30%.

Класичний FP-Growth + нейромережа: rules для високопідтримуваних пар (lift > 1.2, confidence > 0.3), нейромережа для long-tail. Це дає +15-20% Recall@10 проти чистих association rules.

import pandas as pd
import numpy as np
from mlxtend.frequent_patterns import fpgrowth, association_rules
from mlxtend.preprocessing import TransactionEncoder
import torch
import torch.nn as nn

class BasketAnalyzer:
    """Класичний FP-Growth + нейромережеве розширення"""

    def __init__(self, min_support: float = 0.01, min_confidence: float = 0.3):
        self.min_support = min_support
        self.min_confidence = min_confidence
        self.rules = None
        self.te = TransactionEncoder()

    def fit(self, transactions: list[list[str]]) -> pd.DataFrame:
        """
        transactions: [['молоко', 'хлеб', 'масло'], ['молоко', 'яйца'], ...]
        """
        te_array = self.te.fit_transform(transactions)
        df = pd.DataFrame(te_array, columns=self.te.columns_)

        # FP-Growth быстрее Apriori на 10-100x для больших датасетов
        frequent_itemsets = fpgrowth(df, min_support=self.min_support, use_colnames=True)

        self.rules = association_rules(
            frequent_itemsets,
            metric='confidence',
            min_threshold=self.min_confidence
        )

        # Добавляем lift и conviction для фильтрации
        self.rules = self.rules[self.rules['lift'] > 1.2]
        self.rules = self.rules.sort_values('lift', ascending=False)

        return self.rules

    def get_recommendations(self, basket: list[str],
                              top_k: int = 5) -> list[dict]:
        """Рекомендации для текущей корзины"""
        if self.rules is None:
            return []

        basket_set = frozenset(basket)
        matching_rules = self.rules[
            self.rules['antecedents'].apply(lambda x: x.issubset(basket_set))
        ]

        # Убираем товары, уже в корзине
        recommendations = []
        seen = set()
        for _, rule in matching_rules.iterrows():
            for item in rule['consequents']:
                if item not in basket_set and item not in seen:
                    recommendations.append({
                        'item': item,
                        'confidence': rule['confidence'],
                        'lift': rule['lift'],
                        'support': rule['support']
                    })
                    seen.add(item)
                    if len(recommendations) >= top_k:
                        break
            if len(recommendations) >= top_k:
                break

        return recommendations

    def get_category_affinity(self, transactions: pd.DataFrame) -> pd.DataFrame:
        """Матриця афінності між категоріями товарів"""
        # Транзакции с категориями вместо конкретных товаров
        cat_transactions = transactions.groupby('order_id')['category'].apply(list).tolist()
        te_cat = TransactionEncoder()
        cat_array = te_cat.fit_transform(cat_transactions)
        cat_df = pd.DataFrame(cat_array, columns=te_cat.columns_)

        # Совместная встречаемость категорий
        co_occurrence = cat_df.T.dot(cat_df)
        np.fill_diagonal(co_occurrence.values, 0)

        # Нормализуем по поддержке (PMI-подобная мера)
        totals = cat_df.sum()
        n = len(cat_df)
        affinity = co_occurrence / n / (totals.values[:, None] * totals.values[None, :] / n**2 + 1e-9)

        return affinity


class NeuralBasketPredictor(nn.Module):
    """
    Нейросетевая модель для предсказания следующего товара в корзину.
    Входной вектор: bag-of-items бинарный вектор текущей корзины.
    """

    def __init__(self, n_items: int, embedding_dim: int = 64):
        super().__init__()
        self.item_embedding = nn.Embedding(n_items, embedding_dim, padding_idx=0)
        self.attention = nn.MultiheadAttention(embedding_dim, num_heads=4, batch_first=True)
        self.fc = nn.Sequential(
            nn.Linear(embedding_dim, 256),
            nn.ReLU(),
            nn.Dropout(0.3),
            nn.Linear(256, n_items)
        )

    def forward(self, basket_item_ids: torch.Tensor) -> torch.Tensor:
        """
        basket_item_ids: (batch, seq_len) — индексы товаров в корзине
        Returns: (batch, n_items) — logits для каждого товара
        """
        emb = self.item_embedding(basket_item_ids)  # (batch, seq, dim)
        attended, _ = self.attention(emb, emb, emb)  # Self-attention по корзине
        pooled = attended.mean(dim=1)  # (batch, dim)
        return self.fc(pooled)

Як враховувати часові патерни та сезонність?

class TemporalBasketAnalyzer:
    """Аналіз часових патернів покупок"""

    def find_sequential_patterns(self, orders: pd.DataFrame,
                                   days_window: int = 7) -> pd.DataFrame:
        """Виявлення послідовних покупок у вікні N днів"""
        orders_sorted = orders.sort_values(['user_id', 'order_date'])

        sequential = []
        for user_id, user_orders in orders_sorted.groupby('user_id'):
            order_list = user_orders.to_dict('records')
            for i, order_i in enumerate(order_list):
                for order_j in order_list[i+1:]:
                    days_diff = (order_j['order_date'] - order_i['order_date']).days
                    if days_diff > days_window:
                        break
                    if days_diff > 0:
                        sequential.append({
                            'item_a': order_i['sku'],
                            'item_b': order_j['sku'],
                            'days_between': days_diff
                        })

        df = pd.DataFrame(sequential)
        if df.empty:
            return df

        # Топ последовательных пар
        return (df.groupby(['item_a', 'item_b'])
                  .agg(count=('days_between', 'count'),
                       avg_days=('days_between', 'mean'))
                  .reset_index()
                  .sort_values('count', ascending=False))

    def get_seasonal_baskets(self, transactions: pd.DataFrame) -> dict:
        """Сезонні кошики: що зазвичай купують разом у конкретний період"""
        transactions['month'] = transactions['order_date'].dt.month
        transactions['season'] = transactions['month'].map({
            12: 'winter', 1: 'winter', 2: 'winter',
            3: 'spring', 4: 'spring', 5: 'spring',
            6: 'summer', 7: 'summer', 8: 'summer',
            9: 'autumn', 10: 'autumn', 11: 'autumn'
        })

        seasonal_rules = {}
        for season, group in transactions.groupby('season'):
            season_transactions = group.groupby('order_id')['sku'].apply(list).tolist()
            if len(season_transactions) < 100:
                continue

            te = TransactionEncoder()
            arr = te.fit_transform(season_transactions)
            df_season = pd.DataFrame(arr, columns=te.columns_)
            freq = fpgrowth(df_season, min_support=0.02, use_colnames=True)

            if not freq.empty:
                rules = association_rules(freq, metric='lift', min_threshold=1.5)
                seasonal_rules[season] = rules.sort_values('lift', ascending=False).head(20)

        return seasonal_rules

Часові патерни дозволяють рекомендувати товари не тільки на основі одного кошика, але й послідовностей покупок у часі. Наприклад, після покупки принтера через тиждень часто купують картриджі. Сезонні кошики будуються окремо для кожного сезону, що збільшує релевантність рекомендацій. Для кожного користувача система враховує його історію — це дає персоналізовані часові зв'язки.

Процес впровадження: від аудиту до деплою

  1. Аналітика — аудит даних (джерела, якість, частота оновлення). Перевіряємо пропуски, дублікати, розподіл транзакцій.
  2. Проектування — вибір архітектури (гібрид / тільки rules / тільки NN), прототип на вибірці 10k транзакцій.
  3. Реалізація — навчання моделей, написання REST API на FastAPI, інтеграція з CRM/ERP через webhook.
  4. Тестування — A/B-тест на 10% аудиторії, замір CTR та ATC, аналіз lift за категоріями.
  5. Деплой — контейнеризація Docker, розгортання у вашому Kubernetes або хмарі, налаштування моніторингу (Grafana, Prometheus, alerting).

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

  • Навчання 2-3 моделей (FP-Growth, Neural, Temporal) з підбором гіперпараметрів.
  • REST API з документацією (OpenAPI 3.0) — ендпоінти: рекомендації за кошиком, сезонні правила, часові послідовності.
  • Дашборд метрик (Grafana) — recall@k, precision@k, CTR, latency p99.
  • Навчання ваших інженерів (2 воркшопи по 4 години) — архітектура, інтерпретація результатів, донавчання.
  • Гарантійна підтримка 12 місяців з реакцією до 4 годин.

Порівняння підходів: метрики та швидкості

Підхід Recall@10 Час навчання (1M транзакцій) Покриття long-tail Інтерпретованість
Тільки правила 0.42 8 хв Низьке Висока
Тільки нейромережа 0.55 2 год (GPU) Середнє Низька
Гібрид (наш) 0.61 2 год 8 хв Високе Середня

Гібридний підхід дає на 45% більший recall, ніж чисті правила, при цьому зберігає інтерпретованість для топ-пар. Використовуємо його для роздрібних мереж з 50+ магазинів — досвід понад 10 проектів.

Детальніше про метрики precision@k — частка релевантних рекомендацій серед перших k, recall@k — повнота. Для вашого бізнесу важливіший recall@10, якщо ціль — знайти якомога більше відповідних товарів. latency p99 — час відповіді API; гарантуємо < 200ms.
Сценарій Зростання крос-продажів Зниження відтоку Час окупності
Продуктовий рітейл +22% -15% 4-6 міс.
Fashion +18% -10% 6-8 міс.
DIY/товари для дому +25% -12% 5-7 міс.

Отримайте попередню оцінку ваших даних — ми проаналізуємо структуру і запропонуємо оптимальну архітектуру за 2 дні.

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

Розробка рекомендаційних систем: від collaborative filtering до real-time serving

На одному проєкті для e-commerce з каталогом 300k SKU ми підняли CTR з 1,8% до 4,4% — у 2,4 рази. Перший ривок дала колаборативна фільтрація замість «популярне за останні 7 днів», другий — додавання контентних ознак та re-ranking. Різниця між «показуємо популярне» і «показуємо персоналізоване» — вимірна та суттєва. Нижче — інженерний досвід, який допоміг це зробити, і архітектури, які реально працюють у продакшені.

Collaborative Filtering: матрична факторизація та нейронні підходи

Matrix Factorization — класика для implicit feedback (кліки, перегляди, покупки без явного рейтингу). ALS (Alternating Least Squares) у бібліотеці Implicit обробляє матриці user×item із сотнями мільйонів ненульових значень за хвилини на GPU. Latent factors 64–256, регуляризація λ=0.01–0.1 — стартові параметри. Проблема cold start: для нового користувача або товару немає історії — класичний CF безпорадний, потрібні контентні ознаки або гібрид.

Neural Collaborative Filtering (NCF) замінює скалярний добуток на нейромережу. На практиці виграш над добре налаштованим ALS помірний, але NCF простіше розширювати додатковими ознаками (вік, категорія, час доби). Sequence-aware моделі (SASRec, BERT4Rec) враховують порядок взаємодій — state-of-the-art для сесійних рекомендацій.

Як вибрати архітектуру рекомендаційної системи?

Відповідь залежить від даних, навантаження та вимог до холодного старту. Нижче — три основні підходи з критеріями вибору.

Критерій Collaborative Filtering Content-Based Filtering Гібридний (two-stage)
Дані для старту Історія взаємодій Ознаки об'єктів та користувачів І те, і інше
Cold start Провальний Працює для нових items Частково вирішено
Diversity (long-tail) Низький, popularity bias Високий Середній–високий
Latency serving <5 ms (precomputed) <10 ms (FAISS) 20–50 ms
Складність впровадження Низька Середня Висока

Гібридна архітектура на 20–40% ефективніша за чистий CF за покриттям long-tail — перевірено на каталогах від 100k SKU.

Content-Based Filtering: коли історії взаємодій мало

Content-based рекомендує на основі характеристик товарів, а не поведінки інших користувачів — вирішує cold start для нових items. Текстові ембединги через sentence-transformers (multilingual-e5-base, BGE-M3) → пошук схожих через FAISS IndexFlatIP — запит за <5 ms на 100k товарів. Item2Vec (Word2Vec на послідовностях переглядів) дає інтерпретовані «схожі товари» за пару годин навчання.

Структуровані ознаки (категорія, бренд, ціна) подаються через embedding layers або в gradient boosting — CatBoost працює з категоріями без ручного кодування.

Чому гібридні моделі працюють краще?

Production-системи майже завжди дворівневі. Stage 1 (Retrieval) — швидкий відбір 100–500 кандидатів із 300k товарів через ALS або Two-Tower модель з векторним пошуком (FAISS, Qdrant). Stage 2 (Ranking) — важкий ранжувальник на LightGBM або нейромережі з cross-features, часом, пристроєм та контекстом сесії. LightFM — хороша відправна точка для середнього масштабу без важкої інфраструктури. Наша практика показує: перехід від single-stage до two-stage дає приріст точності на 15–25% при зростанні latency всього на 20–30 мс.

Real-Time Serving: архітектура під навантаження

Latency SLA — 50–100 ms при тисячах запитів на секунду. Base-рекомендації precompute (batch job раз на годину) → Redis по user_id → <5 ms. Real-time re-ranking через Kafka для подій (кліки, додавання в кошик) → оновлення контекстних ознак. Feature serving — Redis з TTL (кількість переглядів за 24 години, останній клікнутий item). При навантаженні 10k req/s ставимо Redis Cluster з реплікацією.

A/B тестування — єдиний достовірний спосіб оцінити покращення. Офлайн-метрики корелюють з онлайн не завжди. Kohavi et al., «Online Controlled Experiments at Large Scale» (KDD 2013) — обов'язкове читання для команди. Тест з 5–10% трафіку, моніторинг CTR, конверсії, revenue per session. Одна з наших клієнтських систем після гібридизації збільшила виручку на 18% за місяць A/B.

Терміни розробки рекомендаційної системи

Етапи та типові часові витрати — у таблиці нижче. Вартість розраховується індивідуально під масштаб каталогу та вимоги до latency.

Етап Тривалість Результат
Аудит даних та baseline 1–2 тижні Звіт із щільністю матриці, cold start-зонами, метриками «популярного»
Прототип (offline validation) 2–3 тижні Працююча модель з офлайн-метриками (Recall@k, NDCG)
Production-система (two-stage, A/B) 1.5–2.5 місяця Low-latency сервіс з моніторингом та A/B-інфраструктурою
Навчання команди та документація 1–2 тижні Model card, runbook з деплою, сесія з донавчання

Що входить у розробку під ключ

  1. Аудит даних — щільність матриці user×item (зазвичай <0,1%), розподіл активності, temporal паттерни, cold start статистика.
  2. Baseline — «популярне» як простий поріг, який часто важко перевершити.
  3. Ітеративне покращення — ALS → контентні ознаки → two-stage → sequence-aware. Кожен крок з A/B.
  4. Інфраструктура serving — batch precomputation, Redis, real-time re-ranking, моніторинг у Grafana.
  5. Документація — model card з метриками, інструкція з деплою, опис ознак.
  6. Навчання команди — сесія з інтерпретації результатів та донавчання моделі.
  7. Підтримка — 1 місяць після запуску (фікс інцидентів, доналаштування pipeline).

Ми — команда з 7+ роками досвіду в рекомендаційних системах, реалізували понад 30 проєктів для e-commerce та медіа. Гарантуємо прозоре A/B-тестування та фіксацію покращення метрик.

Хочете оцінити потенціал зростання вашого каталогу? Зв'яжіться з нами для безкоштовного аудиту даних. Замовте розробку рекомендаційної системи — перший прототип протягом двох тижнів.

Приклад конфігу ALS для implicit feedback
from implicit.als import AlternatingLeastSquares

model = AlternatingLeastSquares(
    factors=64,
    regularization=0.05,
    iterations=15,
    use_gpu=True
)
model.fit(user_item_matrix)

Більше про математику рекомендаційних систем — у Wikipedia.