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

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

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

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

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

  • image_website-b2b-advance_0.webp
    Розробка сайту компанії B2B ADVANCE
    1439
  • 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

Розробка 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 тижні. Отримайте консультацію щодо оцінки ваших даних.