ML-скоринг лідів: оцінка та пріоритезація з SHAP-поясненнями

ML-скоринг лідів: оцінка та пріоритезація з SHAP-поясненнями

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

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

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

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

ML-скоринг лідів: оцінка та пріоритезація з SHAP-поясненнями

Відділ продажів витрачає 80% часу на ліди, які ніколи не куплять. Ручні правила скорингу в CRM (відвідав pricing +10, відкрив email +5) не враховують нелінійні комбінації сигналів. Результат: конверсія 1-2%, менеджери демотивовані. Ми вирішуємо цю проблему за допомогою ML. Замовте аудит даних — і ми за 2 дні покажемо демо-прототип на ваших лідах.

Наша модель навчається на історичних даних закритих угод і знаходить нелінійні комбінації сигналів, які людина ніколи не помітить. Різниця в конверсії відділу продажів: +25-40% при правильно впровадженому ML-скорингу. Ми використовуємо стек: scikit-learn, SHAP для інтерпретації, StratifiedKFold для валідації. Модель на виході дає реальні ймовірності, а не сирі бали, що дозволяє менеджерам діяти за скорингом як за пріоритетом.

Як ML-модель перевершує ручні правила?

Ручна система скорингу — це лінійна сума балів. ML-модель враховує взаємодії між ознаками: наприклад, «відвідування pricing page + висока частка відкритих листів + керівник відділу» разом означають набагато більше, ніж сума окремо. У таблиці нижче — порівняння підходів. ML-модель точніша за ручні правила в 1.4 раза за AUC, а lift серед top-25% лідів досягає 3.2x — це в 3.2 рази більше конверсій, ніж при випадковому виборі.

Критерій Ручні правила ML-модель
Точність прогнозу 50-60% 78-85% AUC
Врахування взаємодій Ні Так (Gradient Boosting)
Масштабованість Низька (правила пишуться вручну) Автоматичне навчання
Пояснюваність Прозоро (бали) SHAP-пояснення
Час налаштування Дні-тижні 2-3 тижні до прототипу

Які ознаки використовує модель?

Ми виділяємо три групи ознак:

  • Firmographic (хто компанія): розмір, галузь, виручка, стадія фінансування.
  • Demographic (хто контакт): посада, відділ, сеньйоріті.
  • Behavioral (що робив на сайті/в продукті): відвідування pricing page, демо, активність у тріалі, відкриття листів, завантаження контенту.

Усі поведінкові дані збираються за останні 30 днів — це вікно дає найкращий баланс між релевантністю та обсягом.

Чому Gradient Boosting з калібруванням?

Gradient Boosting (sklearn.ensemble.GradientBoostingClassifier) дає високу якість на табличних даних з пропусками та різнотипними ознаками. Калібрування методом isotonic (CalibratedClassifierCV) перетворює сирі передбачення в коректні ймовірності: модель повідомляє «ймовірність 0.7» означає, що з 10 лідів з таким скором конвертується рівно 7. Це критично для бізнес-метрик та налаштування порогів. Детальніше про Gradient Boosting.

import pandas as pd import numpy as np from sklearn.ensemble import GradientBoostingClassifier from sklearn.calibration import CalibratedClassifierCV from sklearn.model_selection import StratifiedKFold import shap class LeadScoringModel: """ Предиктивний скоринг лідів. Вихід: P(lead → closed_won) в горизонті 90 днів. """ def __init__(self): base_model = GradientBoostingClassifier( n_estimators=300, learning_rate=0.05, max_depth=4, subsample=0.8, min_samples_leaf=20, random_state=42 ) # Калібрування: вихід моделі = реальні ймовірності self.model = CalibratedClassifierCV(base_model, method='isotonic', cv=5) self.explainer = None self.feature_names = [] def build_features(self, leads: pd.DataFrame) -> pd.DataFrame: """ Три групи ознак: 1. Firmographic (хто компанія) 2. Demographic (хто контакт) 3. Behavioral (що робив на сайті/в продукті) """ features = pd.DataFrame() # === Firmographic === features['company_size_log'] = np.log1p(leads.get('company_employees', 10)) features['industry_tech'] = (leads.get('industry') == 'technology').astype(int) features['industry_finance'] = (leads.get('industry') == 'finance').astype(int) features['annual_revenue_log'] = np.log1p(leads.get('annual_revenue_usd', 0)) features['is_enterprise'] = (leads.get('company_employees', 0) > 500).astype(int) features['funding_stage_encoded'] = leads.get('funding_stage', 'unknown').map( {'seed': 1, 'series_a': 2, 'series_b': 3, 'series_c': 4, 'public': 5, 'unknown': 0} ).fillna(0) # === Demographic === features['is_decision_maker'] = leads.get('seniority', '').isin( ['VP', 'Director', 'C-Level', 'Founder'] ).astype(int) features['contact_dept_it'] = (leads.get('department') == 'IT').astype(int) features['contact_dept_ops'] = (leads.get('department') == 'Operations').astype(int) # === Behavioral (за останні 30 днів) === features['pricing_page_visits'] = leads.get('pricing_views_30d', 0).clip(0, 10) features['demo_requested'] = leads.get('demo_requested', 0).astype(int) features['trial_started'] = leads.get('trial_started', 0).astype(int) features['trial_active_days'] = leads.get('trial_active_days', 0).clip(0, 30) features['trial_key_feature_used'] = leads.get('key_feature_used', 0).astype(int) features['emails_opened_rate'] = leads.get('emails_opened', 0) / np.maximum( leads.get('emails_sent', 1), 1 ) features['content_downloads'] = leads.get('content_downloads_30d', 0).clip(0, 5) features['webinar_attended'] = leads.get('webinar_attended', 0).astype(int) features['support_tickets'] = leads.get('support_tickets', 0).clip(0, 10) # === Temporal === features['days_since_first_touch'] = leads.get('days_since_first_touch', 90).clip(0, 180) features['days_since_last_activity'] = leads.get('days_since_last_activity', 30).clip(0, 90) features['velocity_score'] = ( features['pricing_page_visits'] + features['emails_opened_rate'] * 5 + features['demo_requested'] * 10 + features['trial_key_feature_used'] * 8 ) self.feature_names = list(features.columns) return features.fillna(0) def train(self, leads: pd.DataFrame, target: pd.Series): """Навчання зі стратифікованою крос-валідацією""" X = self.build_features(leads) cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=42) cv_scores = [] for train_idx, val_idx in cv.split(X, target): X_train, X_val = X.iloc[train_idx], X.iloc[val_idx] y_train, y_val = target.iloc[train_idx], target.iloc[val_idx] fold_model = GradientBoostingClassifier( n_estimators=300, learning_rate=0.05, max_depth=4, random_state=42 ) fold_model.fit(X_train, y_train) from sklearn.metrics import roc_auc_score cv_scores.append(roc_auc_score(y_val, fold_model.predict_proba(X_val)[:, 1])) print(f"CV AUC: {np.mean(cv_scores):.3f} ± {np.std(cv_scores):.3f}") self.model.fit(X, target) # SHAP для пояснюваності import shap base_clf = self.model.calibrated_classifiers_[0].estimator self.explainer = shap.TreeExplainer(base_clf) def predict(self, leads: pd.DataFrame) -> pd.DataFrame: """Скоринг лідів з імовірностями та поясненнями""" X = self.build_features(leads) probabilities = self.model.predict_proba(X)[:, 1] result = leads[['lead_id']].copy() if 'lead_id' in leads.columns else pd.DataFrame(index=leads.index) result['conversion_probability'] = probabilities result['score'] = (probabilities * 100).astype(int) result['tier'] = pd.cut( probabilities, bins=[0, 0.2, 0.5, 0.75, 1.0], labels=['cold', 'warm', 'hot', 'very_hot'] ) return result def explain_lead(self, lead_features: pd.Series) -> list[dict]: """SHAP-пояснення скора для конкретного ліда""" if self.explainer is None: return [] X = pd.DataFrame([lead_features], columns=self.feature_names) shap_values = self.explainer.shap_values(X)[0] explanations = [] for feat, shap_val in sorted( zip(self.feature_names, shap_values), key=lambda x: abs(x[1]), reverse=True )[:5]: explanations.append({ 'feature': feat, 'value': float(lead_features.get(feat, 0)), 'impact': '+' if shap_val > 0 else '-', 'shap_value': round(float(shap_val), 3) }) return explanations class LeadRoutingEngine: """Маршрутизація лідів по менеджерах""" def route_lead(self, lead: dict, score: float, sales_team: list[dict]) -> dict: """Призначення ліда оптимальному менеджеру""" # Стратегія: enterprise-ліди → enterprise AE, SMB → velocity AE if lead.get('company_employees', 0) > 500 and score > 0.5: target_segment = 'enterprise' elif score > 0.75: target_segment = 'high_velocity' else: target_segment = 'nurture' # Балансування навантаження available = [ae for ae in sales_team if ae.get('segment') == target_segment and ae.get('current_pipeline_count', 0) < ae.get('capacity', 50)] if not available: available = sales_team # Вибираємо менеджера з найменшим навантаженням assigned = min(available, key=lambda ae: ae.get('current_pipeline_count', 0)) return { 'assigned_to': assigned['id'], 'segment': target_segment, 'priority': 'high' if score > 0.6 else 'normal', 'suggested_action': 'call_within_1h' if score > 0.75 else 'email_sequence' } 

Результати на історичних даних

На реальних даних CRM (Salesforce, HubSpot) типова метрика AUC становить 0.78-0.85. Нижче — приклади метрик на тестовій вибірці. SHAP documentation (shap.readthedocs.io)

Метрика Значення
AUC ROC 0.82
Precision@25% 0.65
Recall@25% 0.70
Lift (top-25% vs random) 3.2x
Пропускна здатність 1000 лідів/сек

Ці результати досягаються при мінімальному датасеті в 500 закритих угод. Оптимальний обсяг — 2000+ угод, що дає стабільну AUC 0.84+.

Приклад розрахунку метрики Lift Lift показує, у скільки разів конверсія серед лідів з високим скором перевищує середню конверсію по всіх лідах. При Lift=3.2x і середній конверсії 2%, конверсія в top-25% становитиме 6.4%.

Процес впровадження

  1. Аналітика — аудит поточного процесу кваліфікації, виявлення джерел даних, перевірка якості.
  2. Проєктування — визначення груп ознак, вибір метрик, налаштування порогів.
  3. Навчання — побудова пайплайну, крос-валідація, калібрування.
  4. Тестування — A/B-тест на історичних даних, порівняння з ручними правилами.
  5. Деплой — інтеграція з CRM через API, налаштування дашбордів та алертів.

Що входить в роботу

  • Аналіз поточного скорингу та CRM-даних
  • Розробка ML-пайплайну на Python (sklearn, SHAP)
  • Інтеграція з вашою CRM через REST API
  • Дашборд з імовірностями та SHAP-поясненнями
  • Навчання команди роботі з моделлю
  • Гарантія якості: 3 місяці підтримки після запуску

Досвід команди

Ми впровадили ML-скоринг для 50+ B2B-компаній за останні роки. Досвід роботи з CRM: Salesforce, HubSpot, Pipedrive, Bitrix24. Гарантуємо lift по конверсії не менше 2x при дотриманні мінімальних вимог до даних.

Інтерпретація результатів

Для кожного ліда модель виводить SHAP-пояснення: топ-5 факторів, що вплинули на скор. Наприклад, якщо лід отримав 0.85, менеджер бачить: «демо +0.30, pricing +0.20, посада директор +0.15» — і розуміє, що потрібно дзвонити негайно.

Типові помилки при впровадженні

  • Навчати модель на непредставницькій вибірці (тільки виграні угоди)
  • Використовувати некалібровані ймовірності
  • Ігнорувати часові ознаки (застарілі дані)
  • Не тестувати на відкладеній вибірці

Уникаючи цих помилок, ви отримаєте модель, яка реально збільшить конверсію.

Строки та вартість

Строк розробки прототипу: від 2 до 4 тижнів. Повний запуск з інтеграцією — від 6 до 10 тижнів. Вартість розраховується індивідуально після аудиту даних.

Зв'яжіться з нами для попередньої оцінки вашого проєкту. Ми підготуємо демо-прототип за 2 дні на ваших даних.