共计 2614 个字符,预计需要花费 7 分钟才能阅读完成。
背景痛点:为什么需要决策树推荐?
传统协同过滤在服装推荐中常遇到两个头疼问题:

- 冷启动困境 :新上架商品或新用户没有历史交互数据时,协同过滤完全失效
- 特征稀疏性 :服装品类的属性(颜色 / 尺码 / 风格)往往是非数值型数据,直接套用矩阵分解效果差
举个真实案例:某电商 APP 用协同过滤做连衣裙推荐,新用户首屏出现的全是平台畅销款,导致个性化体验差,点击率不足 3%。
技术选型:CART 决策树的优势
相比 ID3/C4.5 决策树,CART 在服装推荐中优势明显:
- Gini 系数更适合离散特征
- 计算效率高:$Gini(D)=\sum_{k=1}^K p_k(1-p_k)$ 只需遍历特征值
-
对类别特征友好:颜色(红 / 蓝 / 黄)等离散值无需像信息增益那样做对数运算
-
天生支持多分类任务
- 服装推荐本质是多分类问题(预测用户可能点击的品类)
-
CART 的二叉树结构比 ID3 的直接多分裂更稳定
-
可解释性强
- 决策路径如:”IF 颜色 = 红色 AND 价格 <200 THEN 推荐卫衣 ” 业务方可直接理解
核心实现:从数据到模型
特征工程实战
服装数据通常长这样:
sample_item = {'price':199, 'color':'red', 'style':'casual', 'season':'spring'}
需要进行特征编码:
-
离散特征 One-Hot 编码
from sklearn.preprocessing import OneHotEncoder # 假设有 3 种颜色、4 种风格 color_encoder = OneHotEncoder().fit([['red'], ['blue'], ['black']]) style_encoder = OneHotEncoder().fit([['casual'], ['sport'], ['formal'], ['vintage']]) -
连续特征分箱处理
# 将价格分为三档 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 测试要关注:
- CTR 提升 :推荐位点击率对比基线
- 品类覆盖度 :推荐结果中不同风格 / 颜色商品的分布熵
- 新商品曝光量 :解决冷启动能力的关键指标
计算示例:
# 品类覆盖度计算
from scipy.stats import entropy
style_distribution = recommendations['style'].value_counts(normalize=True)
coverage_score = entropy(style_distribution) # 值越大说明覆盖越均匀
延伸思考:GBDT 增强方案
当单棵 CART 树效果达到瓶颈时:
- 使用 LightGBM 的 GBDT 框架
- 保持原有的服装特征处理流程
- 通过早停法控制树的数量
代码示例:
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/ 肩宽等),这会让推荐更加精准。
正文完
