← Назад к вопросам

Как подобрать подходящий оффер для клиента?

2.3 Middle🔥 181 комментариев
#Машинное обучение#Рекомендательные системы

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI29 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Как подобрать подходящий оффер для клиента

Задача рекомендации подходящих офферов одна из ключевых в Data Science. Она решает задачу персонализации и значительно влияет на доход компании. Я опишу несколько подходов от простого к сложному, основываясь на реальном опыте.

Подход 1: Демографический скоринг

Выбираем оффер на основе профиля клиента и характеристик оффера:

import pandas as pd
import numpy as np

clients = pd.DataFrame({
    "client_id": [1, 2, 3, 4, 5],
    "age": [25, 45, 32, 55, 28],
    "income": [30000, 80000, 50000, 120000, 35000],
    "has_family": [0, 1, 1, 1, 0],
})

offers = pd.DataFrame({
    "offer_id": ["A", "B", "C", "D", "E"],
    "min_income": [0, 50000, 40000, 100000, 0],
    "max_income": [50000, 200000, 100000, 500000, 30000],
    "target_age_min": [18, 30, 25, 40, 18],
    "target_age_max": [50, 75, 60, 80, 30]
})

def recommend_offers(client_profile, offers_data):
    recommended = []
    for idx, offer in offers_data.iterrows():
        income_match = (
            offer["min_income"] <= client_profile["income"] <= offer["max_income"]
        )
        age_match = (
            offer["target_age_min"] <= client_profile["age"] <= offer["target_age_max"]
        )
        if income_match and age_match:
            recommended.append(offer["offer_id"])
    return recommended

client = clients.loc[1]
print(recommend_offers(client, offers))

Подход 2: Collaborative Filtering

Рекомендуем офферы, которые нравились похожим клиентам:

from sklearn.metrics.pairwise import cosine_similarity

purchase_history = pd.DataFrame({
    "offer_A": [1, 0, 1, 0, 1],
    "offer_B": [0, 1, 0, 1, 0],
    "offer_C": [1, 1, 1, 0, 1]
}, index=["client_1", "client_2", "client_3", "client_4", "client_5"])

similarity = cosine_similarity(purchase_history)
similarity_df = pd.DataFrame(
    similarity,
    index=purchase_history.index,
    columns=purchase_history.index
)

def collaborative_recommend(target_client, similarity_matrix, purchase_history):
    similar_clients = similarity_matrix[target_client].drop(target_client).nlargest(3)
    recommendations = {}
    
    for offer in purchase_history.columns:
        if purchase_history.loc[target_client, offer] == 0:
            score = purchase_history.loc[similar_clients.index, offer].mean()
            recommendations[offer] = score
    
    return sorted(recommendations.items(), key=lambda x: x[1], reverse=True)

recs = collaborative_recommend("client_1", similarity_df, purchase_history)
print(recs)

Подход 3: ML-модель для вероятности покупки

Обучаем модель предсказывать, купит ли клиент конкретный оффер:

from sklearn.ensemble import RandomForestClassifier

training_data = []
for client_idx, client_row in clients.iterrows():
    for offer_idx, offer_row in offers.iterrows():
        features = [
            client_row["age"],
            client_row["income"],
            offer_row["min_income"],
            offer_row["max_income"],
            offer_row["target_age_min"],
            offer_row["target_age_max"]
        ]
        label = np.random.randint(0, 2)  # Пример
        training_data.append(features + [label])

training_df = pd.DataFrame(training_data, columns=[
    "age", "income",
    "offer_min_income", "offer_max_income",
    "offer_min_age", "offer_max_age",
    "purchased"
])

X = training_df.drop(columns=["purchased"])
y = training_df["purchased"]

model = RandomForestClassifier(n_estimators=100, random_state=42)
model.fit(X, y)

def ml_recommend(client_id, client_data, offers_data, model):
    client = client_data.loc[client_id]
    predictions = []
    
    for offer_idx, offer in offers_data.iterrows():
        features = np.array([[
            client["age"],
            client["income"],
            offer["min_income"],
            offer["max_income"],
            offer["target_age_min"],
            offer["target_age_max"]
        ]])
        
        prob = model.predict_proba(features)[0, 1]
        predictions.append({
            "offer_id": offer["offer_id"],
            "probability": prob
        })
    
    predictions_df = pd.DataFrame(predictions).sort_values(
        by="probability",
        ascending=False
    )
    
    return predictions_df.head(3)

print(ml_recommend(0, clients, offers, model))

Подход 4: A/B тестирование рекомендаций

Валидируем на реальных данных:

from scipy import stats

control_group = {"shown": 1000, "purchased": 120}
test_group = {"shown": 1000, "purchased": 165}

control_cr = control_group["purchased"] / control_group["shown"]
test_cr = test_group["purchased"] / test_group["shown"]

print(f"Control: {control_cr:.4f}")
print(f"Test: {test_cr:.4f}")
print(f"Improvement: {(test_cr - control_cr) / control_cr * 100:.2f} percent")

contingency_table = [
    [control_group["purchased"], control_group["shown"] - control_group["purchased"]],
    [test_group["purchased"], test_group["shown"] - test_group["purchased"]]
]

chi2, p_value = stats.chi2_contingency(contingency_table)[:2]

if p_value < 0.05:
    print("Improvement is statistically significant")
else:
    print("Need more data")

Гибридный подход (рекомендуемый)

Комбинируем несколько методов с взвешиванием:

def hybrid_recommend(
    client_id,
    clients_df,
    offers_df,
    purchase_history_df,
    ml_model,
    weights=None
):
    if weights is None:
        weights = {
            "content": 0.3,
            "collaborative": 0.3,
            "ml": 0.4
        }
    
    all_offers = list(offers_df["offer_id"])
    combined_scores = {}
    
    for offer in all_offers:
        client = clients_df.loc[client_id]
        
        # Content-based score
        offer_row = offers_df[offers_df["offer_id"] == offer].iloc[0]
        content_score = (
            (offer_row["min_income"] <= client["income"] <= offer_row["max_income"]) and
            (offer_row["target_age_min"] <= client["age"] <= offer_row["target_age_max"])
        )
        
        # ML score
        features = np.array([[
            client["age"],
            client["income"],
            offer_row["min_income"],
            offer_row["max_income"],
            offer_row["target_age_min"],
            offer_row["target_age_max"]
        ]])
        ml_score = ml_model.predict_proba(features)[0, 1]
        
        # Combined
        combined_scores[offer] = (
            weights["content"] * (1.0 if content_score else 0.0) +
            weights["collaborative"] * 0.5 +
            weights["ml"] * ml_score
        )
    
    ranked = sorted(
        combined_scores.items(),
        key=lambda x: x[1],
        reverse=True
    )
    
    return ranked[:3]

final_recs = hybrid_recommend(
    0, clients, offers, purchase_history, model
)
print(final_recs)

Ключевые метрики

  • Click-Through Rate (CTR): процент кликов на рекомендацию
  • Conversion Rate (CR): процент кликов, приведших к покупке
  • Average Order Value (AOV): средняя стоимость заказа
  • Precision@K: процент релевантных офферов среди топ K
  • NDCG: учитывает позицию в списке рекомендаций

Лучшие практики

  1. Начни с простого правила (демографические признаки)
  2. Добавь ML модель для улучшения
  3. Всегда А/B тести перед deployment
  4. Мониторь бизнес-метрики в production
  5. Регулярно переучивай модель на новых данных
  6. Избегай холодного старта (cold start problem) для новых клиентов

Для production-системы используй гибридный подход с регулярным A/B тестированием и мониторингом метрик.