О насБлогКонтакты
ИИ и машинное обучение18 июня 2013 г. 3 мин 144Обновлено: 22 июня 2026 г.

Предиктивная аналитика в e-commerce: как ранний ML генерировал «Товары, которые вам понравятся»

AunimedaAunimeda
📋 Содержание

Amazon ввёл «покупатели, купившие это, также купили» в 1998 году. В 2013 мы строили нечто подобное для регионального ритейлера без инфраструктуры Amazon - без Spark, без ML-пайплайнов реального времени, без GPU. Мы построили на SQL, Python и ночном batch-задании. Работало.


Данные: что у нас было

18 месяцев истории заказов. 180 000 выполненных заказов. 42 000 уникальных покупателей. 3 800 товаров. Не «большие данные» - всё это удобно помещалось в MySQL.


Item-based коллаборативная фильтрация

Основной алгоритм: найти товары, которые часто покупают вместе.

Шаг 1: Матрица совместных покупок:

-- Все пары товаров, купленных в одном заказе
CREATE TABLE product_cooccurrence AS
SELECT 
    a.product_id AS product_a,
    b.product_id AS product_b,
    COUNT(DISTINCT a.order_id) AS cooccurrence_count
FROM order_items a
JOIN order_items b ON a.order_id = b.order_id AND a.product_id < b.product_id
JOIN orders o ON a.order_id = o.id
WHERE o.status = 'completed'
GROUP BY a.product_id, b.product_id
HAVING COUNT(DISTINCT a.order_id) >= 3;

Этот запрос работал 4 минуты в production. Сразу перенесли на read-реплику.

Шаг 2: Коэффициент Жаккара:

Сырые подсчёты совместных покупок благоприятствуют популярным товарам. Нормализуем через коэффициент Жаккара: |A ∩ B| / |A ∪ B|.

def calculate_jaccard_similarities(db):
    # Получаем количество заказов на товар
    cursor.execute("""
        SELECT product_id, COUNT(DISTINCT order_id) as order_count
        FROM order_items JOIN orders USING (order_id)
        WHERE orders.status = 'completed'
        GROUP BY product_id
    """)
    order_counts = {row['product_id']: row['order_count'] for row in cursor.fetchall()}
    
    cursor.execute("SELECT product_a, product_b, cooccurrence_count FROM product_cooccurrence")
    
    similarities = []
    for row in cursor.fetchall():
        a, b, co = row['product_a'], row['product_b'], row['cooccurrence_count']
        union = order_counts.get(a, 0) + order_counts.get(b, 0) - co
        jaccard = co / union if union > 0 else 0
        similarities.extend([(a, b, jaccard), (b, a, jaccard)])  # Симметрично
    
    return similarities

def save_recommendations(db, similarities):
    by_product = defaultdict(list)
    for a, b, score in similarities:
        by_product[a].append((b, score))
    
    cursor.execute("TRUNCATE TABLE product_recommendations")
    for product_id, related in by_product.items():
        top_10 = sorted(related, key=lambda x: x[1], reverse=True)[:10]
        for rank, (related_id, score) in enumerate(top_10):
            cursor.execute("""
                INSERT INTO product_recommendations (product_id, recommended_product_id, similarity_score, rank)
                VALUES (%s, %s, %s, %s)
            """, (product_id, related_id, score, rank + 1))

Ночной batch-процесс

# /etc/cron.d/recommendations
# 0 2 * * * recommender /usr/bin/python3 /app/scripts/rebuild_recommendations.py

Время работы: 8 минут на read-реплике. Запись на primary - 2 минуты. Итого: 10 минут, 2:00-2:10, ноль влияния на пользователей.


Результаты A/B теста (30 дней)

Метрика Контроль (без рекомендаций) Тест (с рекомендациями)
Средний чек 2 850 сом 3 420 сом
Товаров в заказе 1.8 2.3
Кликабельность рекомендаций - 8.4%
Конверсия рекомендаций - 14.2%

Средний чек вырос на 20%. Система рекомендаций окупила себя на второй неделе A/B теста.

Кликабельность 8.4% значительно выше отраслевых бенчмарков (2-4% для email-рекомендаций). Разница: контекстные рекомендации на странице товара vs рекламные рассылки. Релевантность в контексте конвертирует намного лучше, чем релевантность без контекста.


Ограничения и что пришло после

Проблема холодного старта: новые товары не имели истории покупок → не было совместных покупок → нет рекомендаций. Решение: использовать сходство по категории как запасной вариант.

Новые пользователи: нет истории покупок → рекомендации на основе популярности (топ заказов за последние 30 дней) + фильтрация по истории просмотров сессии.

К 2015-2016 годам Apache Spark и MLlib упростили системы рекомендаций. К 2020 - облачные ML-сервисы (AWS Personalize) сделали это задачей конфигурации.

Но алгоритм - коллаборативная фильтрация через совместные покупки и коэффициент Жаккара - остаётся фундаментом. Инфраструктура изменилась; математика - нет.

Читайте также

ИИ в интернет-магазине: персонализация, рекомендации и автоматизация для бизнеса в Бишкекеaunimeda
ИИ и машинное обучение

ИИ в интернет-магазине: персонализация, рекомендации и автоматизация для бизнеса в Бишкеке

Как ИИ увеличивает средний чек и конверсию интернет-магазина: рекомендации, поиск по фото, динамическое ценообразование и чат-боты. Реальные цифры для рынка Кыргызстана.

Ранние NLP: строим чат-боты до эпохи LLMaunimeda
ИИ и машинное обучение

Ранние NLP: строим чат-боты до эпохи LLM

В 2013 мы построили бота поддержки клиентов с regex-паттернами, деревьями решений и классификатором Naive Bayes. Никаких нейросетей, никаких эмбеддингов. Вот как выглядело rule-based NLP на самом деле.

Компьютерное зрение: первые попытки OCR в мобильных приложенияхaunimeda
ИИ и машинное обучение

Компьютерное зрение: первые попытки OCR в мобильных приложениях

В 2013 мы построили приложение для авансовых отчётов, читающее чеки через Tesseract OCR на iOS. Точность была 68%. Вот что работало, что нет, и что на самом деле означает предобработка изображений.

Нужна IT-разработка для вашего бизнеса?

Разрабатываем сайты, мобильные приложения и AI-решения для бизнеса в Кыргызстане. Бесплатная консультация.

Получить консультацию Все статьи