Skip to content

第5章 购买意图预测模型 ​

5.1 为什么需要意图预测 ​

在决定"发不发券"之前,我们首先需要回答一个基础问题:这个用户有多大可能完成首单?

购买意图模型(Intent Model)就是对这个问题的量化回答。它预测的是:

P(convert=1∣X)

即给定用户特征 X,用户在观察窗口(7 天)内完成首单的概率。

意图预测 vs Uplift 预测

意图模型回答"用户会不会买",Uplift 模型回答"发券能不能让不买的人买"。两者是互补关系:

  • 意图模型帮助我们理解用户(高意图 vs 低意图)
  • Uplift 模型帮助我们决定干预(发券 vs 不发券)

在实际系统中,意图分数常作为 Uplift 模型的输入特征之一,也用于兜底策略的优先级排序。

5.2 模型设计 ​

问题定义 ​

要素定义
任务类型二分类
标签用户在注册后 7 天内是否完成首单(0/1)
特征第 4 章的浏览特征 + 用户画像特征
评估指标AUC、LogLoss

为什么选择 LightGBM ​

对于这类表格数据 + 特征工程的场景,GBDT(梯度提升树)是工业界的首选:

  1. 天然处理非线性:不需要手动构造交叉特征
  2. 对缺失值鲁棒:LightGBM 内置缺失值处理
  3. 训练速度快:相比 XGBoost 快 2-5 倍
  4. 内存效率高:直方图算法大幅降低内存占用

什么时候考虑深度学习?

当你有序列行为数据(如用户点击流的时间序列)或多模态特征(图片 + 文本 + 数值)时,DIN、DIEN 等深度模型会更有优势。对于本项目的静态聚合特征,树模型足够。

5.3 实现详解 ​

模型类结构 ​

python
# src/models/intent_model.py

class IntentModel:
    """基于 LightGBM 的用户购买意图二分类模型."""

    def __init__(self, params: LGBMParams | None = None) -> None:
        self._params = params or default_lgbm_params
        self._model: lgb.LGBMClassifier | None = None
        self._feature_names: list[str] = []

设计要点:

  • 参数外部化:通过 LGBMParams dataclass 传入,方便统一管理和调参
  • 延迟初始化:_model 初始为 None,训练后才赋值,预测时会检查

训练流程 ​

python
# src/models/intent_model.py

def train(self, X: pd.DataFrame, y: pd.Series) -> dict:
    """训练模型,内部 80/20 split + early stopping."""
    X_train, X_val, y_train, y_val = train_test_split(
        X, y, test_size=0.2, random_state=self._params.random_state, stratify=y,
    )
    self._feature_names = list(X.columns)

    p = self._params.to_dict()
    p["objective"] = "binary"
    self._model = lgb.LGBMClassifier(**p)
    self._model.fit(
        X_train,
        y_train,
        eval_set=[(X_val, y_val)],
        callbacks=[lgb.early_stopping(50, verbose=False), lgb.log_evaluation(-1)],
    )

    y_pred = self._model.predict_proba(X_val)[:, 1]
    return {
        "auc": float(roc_auc_score(y_val, y_pred)),
        "logloss": float(log_loss(y_val, y_pred)),
    }

几个关键设计决策:

① stratify 分层抽样

python
train_test_split(..., stratify=y)

新用户首单转化率通常只有 5%-15%,这是一个类别不平衡问题。stratify=y 确保训练集和验证集中正样本比例一致,避免验证集中正样本过少导致评估不稳定。

② Early Stopping

python
callbacks=[lgb.early_stopping(50, verbose=False)]

设置 n_estimators=500 作为上界,在验证集上连续 50 轮无提升时自动停止。这是防止过拟合的最重要手段——比调正则化参数更有效。

③ 返回验证指标

训练方法直接返回 AUC 和 LogLoss,调用方不需要再额外写评估代码:

  • AUC:衡量排序能力,"高意图用户是否排在前面"
  • LogLoss:衡量概率校准,"预测 0.8 的用户是否真的有 80% 转化"

推理与特征重要度 ​

python
# src/models/intent_model.py

def predict(self, X: pd.DataFrame) -> np.ndarray:
    """返回首单转化概率 (shape (n,))."""
    self._check_fitted()
    return self._model.predict_proba(X)[:, 1]

def feature_importance(self) -> pd.DataFrame:
    """返回按重要度降序排列的特征重要度表."""
    self._check_fitted()
    imp = self._model.feature_importances_
    df = pd.DataFrame({"feature": self._feature_names, "importance": imp})
    return df.sort_values("importance", ascending=False).reset_index(drop=True)

feature_importance() 返回的是 LightGBM 内置的 split 重要度(特征被用于分裂的次数)。在实际项目中,建议同时关注:

重要度类型含义适用场景
split特征被用作分裂的次数发现"常用"特征
gain特征带来的信息增益总量发现"关键"特征
SHAP每个样本的特征贡献模型可解释性报告

模型持久化 ​

python
# src/models/intent_model.py

def save(self, path: str) -> None:
    self._check_fitted()
    joblib.dump({"model": self._model, "feature_names": self._feature_names}, path)

@classmethod
def load(cls, path: str) -> IntentModel:
    data = joblib.load(path)
    obj = cls()
    obj._model = data["model"]
    obj._feature_names = data["feature_names"]
    return obj

使用 joblib 序列化,同时保存 feature_names。这是为了在加载后能验证输入特征与训练时一致——特征漂移是线上事故的常见原因。

5.4 LightGBM 参数解读 ​

我们在 config.py 中定义了统一的 LightGBM 参数:

python
# src/config.py

@dataclass
class LGBMParams:
    objective: str = "binary"
    n_estimators: int = 500
    learning_rate: float = 0.05
    num_leaves: int = 63
    feature_fraction: float = 0.8
    bagging_fraction: float = 0.8
    bagging_freq: int = 5
    min_child_samples: int = 50
    reg_alpha: float = 0.1
    reg_lambda: float = 0.1
    verbose: int = -1
    random_state: int = 42
参数值作用
learning_rate0.05步长较小,配合 early stopping 效果最佳
num_leaves63控制单棵树复杂度,26−1
feature_fraction0.8每棵树随机选 80% 特征,降低过拟合
bagging_fraction0.8每棵树随机选 80% 样本
min_child_samples50叶子节点最少 50 个样本,防止在噪声上过拟合
reg_alpha / reg_lambda0.1L1/L2 正则化

调参建议

工业实践中,最值得调的参数按优先级排序:

  1. learning_rate + n_estimators(配合 early stopping)
  2. num_leaves + min_child_samples(控制树复杂度)
  3. feature_fraction + bagging_fraction(随机性)

不要花太多时间在正则化参数上,early stopping 已经是最好的正则化。

5.5 本章小结 ​

本章实现了购买意图预测模型,核心要点:

  1. 问题定义:二分类任务,预测新用户 7 天内首单概率
  2. 模型选择:LightGBM 二分类,适合表格特征场景
  3. 训练策略:stratify 分层 + early stopping 50 轮,兼顾样本不平衡和过拟合
  4. 评估指标:AUC(排序能力)+ LogLoss(概率校准)
  5. 工程实践:参数外部化、特征名保存、joblib 持久化

意图模型是整个系统的"基础视力"——它让我们看到每个用户的转化可能性。但知道"谁会买"还不够,我们更需要知道"谁因为券才买"。下一章的 Uplift 模型将回答这个关键问题。

思考题 ​

  1. 如果正样本比例只有 3%,你会如何调整训练策略?(提示:考虑 scale_pos_weight、过采样 SMOTE、或调整阈值)
  2. Early stopping 的 patience 设为 50 是否合理?太大或太小分别有什么风险?
  3. 意图模型的预测结果如何与 Uplift 模型配合使用?两个模型的预测结果是否需要校准?

基于 Uplift Modeling 的电商优惠券智能发放系统