从零构建基于CART决策树的服装推荐系统:原理与实战指南

1次阅读
没有评论

共计 2614 个字符,预计需要花费 7 分钟才能阅读完成。

image.webp

背景痛点:为什么需要决策树推荐?

传统协同过滤在服装推荐中常遇到两个头疼问题:

从零构建基于 CART 决策树的服装推荐系统:原理与实战指南

  • 冷启动困境 :新上架商品或新用户没有历史交互数据时,协同过滤完全失效
  • 特征稀疏性 :服装品类的属性(颜色 / 尺码 / 风格)往往是非数值型数据,直接套用矩阵分解效果差

举个真实案例:某电商 APP 用协同过滤做连衣裙推荐,新用户首屏出现的全是平台畅销款,导致个性化体验差,点击率不足 3%。

技术选型:CART 决策树的优势

相比 ID3/C4.5 决策树,CART 在服装推荐中优势明显:

  1. Gini 系数更适合离散特征
  2. 计算效率高:$Gini(D)=\sum_{k=1}^K p_k(1-p_k)$ 只需遍历特征值
  3. 对类别特征友好:颜色(红 / 蓝 / 黄)等离散值无需像信息增益那样做对数运算

  4. 天生支持多分类任务

  5. 服装推荐本质是多分类问题(预测用户可能点击的品类)
  6. CART 的二叉树结构比 ID3 的直接多分裂更稳定

  7. 可解释性强

  8. 决策路径如:”IF 颜色 = 红色 AND 价格 <200 THEN 推荐卫衣 ” 业务方可直接理解

核心实现:从数据到模型

特征工程实战

服装数据通常长这样:

sample_item = {'price':199, 'color':'red', 'style':'casual', 'season':'spring'}

需要进行特征编码:

  1. 离散特征 One-Hot 编码

    from sklearn.preprocessing import OneHotEncoder
    
    # 假设有 3 种颜色、4 种风格
    color_encoder = OneHotEncoder().fit([['red'], ['blue'], ['black']])
    style_encoder = OneHotEncoder().fit([['casual'], ['sport'], ['formal'], ['vintage']])

  2. 连续特征分箱处理

    # 将价格分为三档
    price_bins = [0, 100, 300, float('inf')]
    data['price_group'] = pd.cut(data['price'], bins=price_bins, labels=['low','mid','high'])

CART 树分裂实现

关键代码段(完整实现见 GitHub):

def gini_impurity(labels):
    # 计算基尼不纯度
    _, counts = np.unique(labels, return_counts=True)
    probabilities = counts / len(labels)
    return 1 - np.sum(probabilities**2)

def find_best_split(X, y):
    best_gini = float('inf')
    best_feature = None

    for feature_idx in range(X.shape[1]):
        # 对当前特征所有可能分割点计算 Gini
        unique_values = np.unique(X[:, feature_idx])
        for value in unique_values:
            left_mask = X[:, feature_idx] <= value
            left_gini = gini_impurity(y[left_mask])
            right_gini = gini_impurity(y[~left_mask])
            weighted_gini = (left_gini * sum(left_mask) + 
                            right_gini * sum(~left_mask)) / len(y)

            if weighted_gini < best_gini:
                best_gini = weighted_gini
                best_feature = (feature_idx, value)
    return best_feature

生产环境优化策略

防止过拟合的剪枝方法

使用 CCP(Cost Complexity Pruning):

from sklearn.tree import DecisionTreeClassifier

clf = DecisionTreeClassifier(ccp_alpha=0.02)  # 通过交叉验证选择 alpha
clf.fit(X_train, y_train)

时序特征处理技巧

用户点击行为的时间模式很重要:

  • 最近 3 天点击某类商品的次数
  • 历史点击时间段的统计(如夜间占比)
  • 点击间隔的均值 / 方差

可用 pandas 快速计算:

df['is_night'] = (df['click_hour'] >= 20) | (df['click_hour'] <= 6)
user_features = df.groupby('user_id').agg({
    'item_id': 'count',
    'is_night': 'mean'  # 夜间活跃度
})

模型部署方案

推荐使用 PMML 格式跨平台部署:

from sklearn2pmml import sklearn2pmml

sklearn2pmml(pipeline, "model.pmml", with_repr=True)

效果验证指标

A/ B 测试要关注:

  1. CTR 提升 :推荐位点击率对比基线
  2. 品类覆盖度 :推荐结果中不同风格 / 颜色商品的分布熵
  3. 新商品曝光量 :解决冷启动能力的关键指标

计算示例:

# 品类覆盖度计算
from scipy.stats import entropy

style_distribution = recommendations['style'].value_counts(normalize=True)
coverage_score = entropy(style_distribution)  # 值越大说明覆盖越均匀 

延伸思考:GBDT 增强方案

当单棵 CART 树效果达到瓶颈时:

  1. 使用 LightGBM 的 GBDT 框架
  2. 保持原有的服装特征处理流程
  3. 通过早停法控制树的数量

代码示例:

import lightgbm as lgb

params = {
    'objective': 'multiclass',
    'num_class': 10,  # 假设有 10 个服装品类
    'metric': 'multi_logloss',
    'max_depth': 5    # 保持树的浅层结构
}
model = lgb.train(params, train_data, valid_sets=[valid_data])

实践心得

经过多个服装推荐项目验证,CART 决策树特别适合这样的场景:

  • 需要快速上线 MVP 版本时(2 天可完成 POC)
  • 运营人员需要解释推荐理由时
  • 商品属性维度明确且有限时

下次可以试试加入用户身材特征(BMI/ 肩宽等),这会让推荐更加精准。

正文完
 0
评论(没有评论)