חיזוי CTR/CVR מבוסס בינה מלאכותית לקמפיינים פרסומיים
אתם משיקים קמפיין פרסומי עם מיליון חשיפות ביום. חיזוי CTR מוערך בחסר ב-15% — אתם מפסידים עמדות מכירה פומבית מובילות. מוערך ביתר ב-20% — אתם מבזבזים תקציב על קליקים לא רלוונטיים. אנו פותרים זאת עם מודלי ML מותאמים אישית מקצה לקצה. מערכת הבינה המלאכותית שלנו לחיזוי CTR/CVR מנתחת קהל, הקשר ונתונים היסטוריים כדי לבצע אופטימיזציה של הצעות מחיר בזמן אמת. שגיאה של 20% בחיזוי CTR יכולה לעלות 15-25% מתקציב הפרסום — כסף שאבד על חשיפות לא אפקטיביות.
CTR ו-CVR הם אותות יסודיים לתמחור בפרסום תוכנתי. שגיאה של 20% בחיזוי CTR מתורגמת ישירות לתשלום יתר או להפסד במכירות פומביות. בקנה מידה של מאות מיליוני חשיפות יומיות, אפילו שיפור AUC מ-0.76 ל-0.78 משמעותו מיליונים שנחסכים או נצברו. לפי הנתונים שלנו, LightGBM עם כיול עולה על רגרסיה לוגיסטית ב-0.03-0.05 AUC — השוואה ישירה של יעילות.
כיצד אנו בונים מודלי CTR מקצה לקצה
חיזוי CTR הוא סיווג בינארי עם שלושה אתגרים מרכזיים: חוסר איזון קיצוני בין מחלקות (CTR 0.1-2%), נפח עצום (מיליארדי דוגמאות יומיות), והמרות נסתרות (CVR נצפה רק עבור קליקים, מה שיוצר הטיית בחירה). אנו משתמשים ב-LightGBM עם כוונון scale_pos_weight וכיול לאחר מכן. LightGBM מכויל מניב Log Loss נמוך פי 1.3 מהסתברויות גולמיות.
import numpy as np
import pandas as pd
import lightgbm as lgb
from sklearn.calibration import CalibratedClassifierCV
from sklearn.metrics import roc_auc_score, log_loss
class CTRFeatureEngineer:
"""ÐÑизнаки Ð´Ð»Ñ CTR-модели в display advertising"""
def build_features(self, bid_logs: pd.DataFrame) -> pd.DataFrame:
"""
bid_logs: иÑÑоÑиÑеÑкие логи показов Ñ Ñлагами clicked/converted
"""
df = bid_logs.copy()
# === СÑаÑиÑÑиÑеÑкие пÑизнаки полÑзоваÑÐµÐ»Ñ ===
user_stats = df.groupby('user_id').agg(
user_historical_ctr=('clicked', 'mean'),
user_impression_count=('clicked', 'count'),
user_conversion_rate=('converted', 'mean'),
).reset_index()
# === СÑаÑиÑÑиÑеÑкие пÑизнаки плоÑадки ===
site_stats = df.groupby('site_domain').agg(
site_ctr=('clicked', 'mean'),
site_conversion_rate=('converted', 'mean'),
site_volume=('clicked', 'count'),
).reset_index()
# === ÐÑизнаки пеÑеÑеÑÐµÐ½Ð¸Ñ (user à ad) ===
df['hour'] = pd.to_datetime(df['timestamp']).dt.hour
df['is_weekend'] = pd.to_datetime(df['timestamp']).dt.dayofweek >= 5
df['is_prime_time'] = df['hour'].between(18, 22)
# Cross-пÑизнаки: важнее одиноÑнÑÑ
df['ad_position_encoded'] = df['ad_position'].map({'atf': 1, 'btf': 0}).fillna(0.5)
df = df.merge(user_stats, on='user_id', how='left')
df = df.merge(site_stats, on='site_domain', how='left')
# Smoothed CTR Ð´Ð»Ñ Ð±Ð¾ÑÑÐ±Ñ Ñ ÑазÑеженноÑÑÑÑ (Wilson smoothing)
alpha = 100 # Prior strength
global_ctr = df['clicked'].mean()
df['user_smooth_ctr'] = (
df['user_historical_ctr'].fillna(global_ctr) * df['user_impression_count'].fillna(0) + global_ctr * alpha
) / (df['user_impression_count'].fillna(0) + alpha)
feature_cols = [
'user_smooth_ctr',
'user_impression_count',
'site_ctr',
'site_volume',
'hour',
'is_weekend',
'is_prime_time',
'ad_position_encoded',
'banner_width',
'banner_height',
'floor_price',
]
return df[feature_cols].fillna(0)
class CTRModel:
"""LightGBM Ð´Ð»Ñ CTR Ñ Ð¿ÑавилÑной калибÑовкой"""
def __init__(self):
self.model = lgb.LGBMClassifier(
n_estimators=1000,
learning_rate=0.03,
num_leaves=255,
min_child_samples=200,
subsample=0.8,
colsample_bytree=0.7,
scale_pos_weight=50, # ÐоÑÑекÑÐ¸Ñ Ð´Ð¸ÑбаланÑа: 1 клик на 50 показов
random_state=42,
n_jobs=-1,
)
self.calibrator = None
self._is_calibrated = False
def train(self, X_train: np.ndarray, y_train: np.ndarray, X_val: np.ndarray, y_val: np.ndarray):
"""ÐбÑÑение Ñ Ñанней оÑÑановкой"""
self.model.fit(
X_train,
y_train,
eval_set=[(X_val, y_val)],
eval_metric='auc',
callbacks=[
lgb.early_stopping(100, verbose=False),
lgb.log_evaluation(200)
]
)
# ÐалибÑовка â ÐÐЯÐÐТÐÐЬÐÐ Ð´Ð»Ñ Ð¸ÑполÑÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð² bid price calculation
# СÑÑой LightGBM даÑÑ Ñ
оÑоÑий ranking, но плоÑ
ие веÑоÑÑноÑÑи
self.calibrator = CalibratedClassifierCV(self.model, cv='prefit', method='isotonic')
self.calibrator.fit(X_val, y_val)
self._is_calibrated = True
def predict_ctr(self, X: np.ndarray) -> np.ndarray:
"""ÐалибÑованнÑе веÑоÑÑноÑÑи кликов"""
if self._is_calibrated:
return self.calibrator.predict_proba(X)[:, 1]
return self.model.predict_proba(X)[:, 1]
def evaluate(self, X_test: np.ndarray, y_test: np.ndarray) -> dict:
raw_probs = self.model.predict_proba(X_test)[:, 1]
cal_probs = self.predict_ctr(X_test) if self._is_calibrated else raw_probs
return {
'auc_raw': round(roc_auc_score(y_test, raw_probs), 4),
'auc_calibrated': round(roc_auc_score(y_test, cal_probs), 4),
'logloss_raw': round(log_loss(y_test, raw_probs), 4),
'logloss_calibrated': round(log_loss(y_test, cal_probs), 4),
'mean_predicted_ctr': round(float(cal_probs.mean()), 5),
'actual_ctr': round(float(y_test.mean()), 5),
}
class DelayedConversionCorrector:
"""
ÐоÑÑекÑÐ¸Ñ delayed conversions в CVR-модели.
ÐонвеÑÑии могÑÑ Ð¿ÑоиÑÑ
одиÑÑ ÑеÑез ÑаÑÑ/дни поÑле клика.
ÐбÑезка обÑÑаÑÑей вÑбоÑки по вÑемени ÑоздаÑÑ ÑмеÑение.
"""
def adjust_for_delayed_conversions(self, clicks: pd.DataFrame, observation_window_hours: int = 24) -> pd.DataFrame:
"""
ÐÑбÑаÑÑваем недавние клики, Ñ ÐºÐ¾ÑоÑÑÑ
еÑÑ Ð½Ðµ иÑÑÑк window конвеÑÑии.
ÐнаÑе CVR бÑÐ´ÐµÑ Ð·Ð°Ð½Ð¸Ð¶ÐµÐ½ Ð´Ð»Ñ Ð¿Ð¾ÑледниÑ
пÑимеÑов.
"""
cutoff = pd.Timestamp.now() - pd.Timedelta(hours=observation_window_hours)
return clicks[clicks['click_time'] < cutoff]
def estimate_conversion_delay_distribution(self, conversions: pd.DataFrame) -> dict:
"""РаÑпÑеделение задеÑжек конвеÑÑий"""
delays = (conversions['conversion_time'] - conversions['click_time']).dt.total_seconds() / 3600
return {
'p50_hours': round(float(delays.quantile(0.50)), 1),
'p90_hours': round(float(delays.quantile(0.90)), 1),
'p99_hours': round(float(delays.quantile(0.99)), 1),
'recommended_window': f"{int(delays.quantile(0.95))} hours",
}
"} כיצד להעריך איכות מודל CTR?
מדדים מרכזיים: AUC-ROC (>0.75 טוב), Log Loss (<0.10), ושגיאת כיול (<0.005). בסביבת ייצור, יש לבדוק גם ΔAUC מתכונות חדשות — עלייה של >0.001 מצדיקה מאמץ הנדסי. LightGBM מכויל מניב Log Loss נמוך פי 1.3 מהסתברויות גולמיות.
מדוע כיול הסתברויות הוא קריטי?
מודל לא מכויל יכול לשלם יתר באופן שיטתי במכירות פומביות. LightGBM גולמי נותן דירוגים מצוינים אך הסתברויות חלשות. אנו משתמשים ברגרסיה איזוטונית, שמפחיתה את שגיאת הכיול ל-<0.005. זה קריטי לחישוב מחיר הצעה: אם המודל חוזה CTR של 0.5% אך בפועל הוא 0.8%, אתם משלמים יתר על כל קליק. כיול מדויק חוסך תקציב ישירות — החיסכון מהפעלת מודל LightGBM מכויל יכול להגיע עד 30% מהוצאות הפרסום.
עדכוני מודל שבועיים
הנוף הפרסומי משתנה במהירות: קריאייטיבים חדשים, עונתיות, שינויים בהתנהגות קהל. אנו ממליצים על אימון מחדש שבועי. לשם כך, אנו מקימים צינור אימון מחדש אוטומטי עם ניטור סחיפת תכונות. בתקופות תנודתיות גבוהה (למשל, Black Friday), ייתכן שיידרשו עדכונים יומיים, אך בדרך כלל זה מוגזם ומכניס רעש.
המרות מושהות: בעיה ופתרון
במודלי CVR, המרות יכולות להתרחש שעות או ימים לאחר קליק. אם פשוט חותכים את קבוצת האימון לפי זמן, תצפיות אחרונות יקבלו הערכת CVR נמוכה מדי. אנו משתמשים בתיקון על ידי השלכת קליקים עם חלון המרה שלא פג (בדרך כלל 24-72 שעות בהתאם להתפלגות העיכוב). זה משפר את כיול CVR ב-10-20%.
התפלגות עיכוב המרה אופיינית למסחר אלקטרוני
| אחוזון | עיכוב (שעות) |
|---|---|
| p50 | 2.5 |
| p90 | 18.0 |
| p99 | 72.0 |
| חלון מומלץ | 95 שעות |
מדדי איכות למודל CTR/CVR
| מדד | ערך טוב | מטרה |
|---|---|---|
| AUC-ROC | > 0.75 עבור CTR | יכולת דירוג |
| Log Loss | < 0.10 | איכות הסתברויות |
| שגיאת כיול | < 0.005 | דיוק הערכות CTR |
| NDCG@1000 | > 0.85 | מכירות פומביות מובילות |
| Delta AUC מתכונה חדשה | > 0.001 | החזר הנדסי |
עבור מודלי CTR, AUC 0.76 לעומת 0.74 הוא הבדל משמעותי בקנה מידה. כיול הוא חובה: מודל לא מכויל יכול לשלם יתר באופן שיטתי.
תהליך יישום חיזוי CTR/CVR מבוסס בינה מלאכותית
אנו עובדים בשלבים:
- ביקורת נתונים — איסוף לוגי חשיפות, בדיקת איכות ושלמות. הערכת פוטנציאל שיפור ML.
- הנדסת תכונות — בניית תכונות: CTR מחליק, סטטיסטיקות אתר, דפוסי זמן. שימוש בהחלקת Wilson לטיפול בדלילות.
- אימון וכיול — LightGBM + כיול איזוטוני. אימות על קבוצת בדיקה מופרדת.
- בדיקות A/B — השוואה עם קו בסיס על הכנסות בסביבת ייצור.
- תיעוד ופריסה — ייצוא המודל ל-ONNX או Triton, הקמת ניטור סחיפה.
מה כלול בפיתוח מודל
תוצרים:
- דוח ביקורת נתונים עם הערכת פוטנציאל שיפור
- חבילת Python עם צינור חיזוי
- תיעוד API עבור מערכת הצעות המחיר
- הכשרה לצוות הלקוח
- תמיכה ל-3 חודשים לאחר הפריסה
טעויות אופייניות ב-CTR/CVR MVP
- התעלמות מהמרות מושהות — CVR מוערך בחסר ב-10-20%.
- חוסר אימות: שימוש ב-cross-validation יחיד במקום בשלושה holdouts מבוססי זמן.
- עדכונים תכופים מדי (יומיים) — רעש מתנודות אקראיות.
- שימוש במודלים ליניאריים בלבד — הם מפספסים אינטראקציות לא ליניאריות.
הזמינו ביקורת נתונים על נתוני הפרסום שלכם — נקבע את פוטנציאל שיפור ה-CTR. קבלו ייעוץ: נעריך את הנתונים שלכם ונספר לכם איזה שיפור CTR אפשרי. הניסיון שלנו: למעלה מ-20 פרויקטים לפלטפורמות תוכנתיות, 5+ שנים באופטימיזציית ML לפרסום. צרו קשר לייעוץ על הנתונים שלכם.







