1. 特征工程:推荐系统的"食材预处理"阶段
做一道好菜的关键是什么?很多人会说是厨师的烹饪技术,但真正的大厨都知道,食材的选择和处理才是决定菜品质量的基础。推荐系统也是如此——模型算法相当于厨师的烹饪技术,而特征工程就是食材的挑选、清洗和切配过程。
我在电商平台负责推荐系统优化时,曾遇到一个典型案例:当我们把用户点击率从3.2%提升到5.8%,团队第一反应是升级模型架构。但经过数据分析发现,仅仅是优化了用户历史行为的时间衰减系数这一特征,就带来了1.3%的提升。这让我深刻认识到,特征质量直接决定了模型效果的天花板。
1.1 什么是特征工程
特征工程是将原始数据转化为更能代表问题本质的特征的过程。就像厨师不会直接把整颗白菜扔进锅里,我们也不能把原始日志数据直接喂给模型。举个例子:
- 原始数据:用户A在2023-08-20 14:30:00点击了商品B
- 基础特征:用户ID、商品ID、点击时间
- 工程化特征:
- 用户过去7天同类商品的点击频次
- 该商品在当前session中的出现顺序
- 点击时间与用户通常活跃时段的偏差值
1.2 推荐系统中的特征分类
根据我在多个项目的实践经验,推荐系统的特征通常分为三大类:
用户画像特征
- 静态属性:年龄、性别、注册信息
- 动态行为:近期点击序列、购买周期、页面停留时长
- 隐含偏好:通过Embedding学习得到的用户向量
物品画像特征
- 商品类目、价格段、上架时间
- 内容型物品的文本特征(如视频标题的关键词)
- 多模态特征(商品主图的视觉特征)
上下文特征
- 时间特征:小时段、是否节假日
- 设备特征:移动端/PC端、网络类型
- 场景特征:搜索关键词、推荐触发位置
实战经验:在新用户冷启动场景中,上下文特征的权重往往需要调高。我们曾通过强化地理位置和当前时间特征,将新用户首日点击率提升了40%。
2. 特征处理的核心方法论
2.1 特征提取:从原始数据中"采矿"
处理电商用户行为日志时,我常用的提取方法包括:
python复制# 用户行为序列特征提取示例
def extract_sequence_features(df):
# 计算用户最近10次点击的时间衰减权重
df['time_decay'] = np.exp(-0.1 * (df['max_time'] - df['click_time']))
# 统计类目偏好
cate_count = df.groupby(['user_id', 'category'])['item_id'].count().unstack()
# 构建用户行为序列
seq_features = df.groupby('user_id').apply(
lambda x: x.sort_values('click_time')['item_id'].tolist()
)
return cate_count, seq_features
关键技巧:
- 时间衰减系数:用户3天前的点击比3个月前的更有参考价值
- 行为强度归一化:将绝对点击次数转换为在同类用户中的百分位
- 会话分割:识别连续活跃时段作为独立分析单元
2.2 特征构造:创造有意义的"组合食材"
好的特征构造就像食材的搭配组合。我们团队总结出几个有效模式:
-
交叉特征:
- 用户年龄分段 × 商品价格段
- 用户活跃时段 × 商品类目
-
统计特征:
- 用户历史点击率的滑动窗口均值
- 商品被不同年龄段用户点击的分布熵
-
序列特征:
- 用户最近浏览的5个商品的类目转移矩阵
- 基于注意力机制的关键行为提取
python复制# 构建交叉特征示例
def build_cross_features(user_df, item_df):
# 用户购买力等级 (基于历史订单)
user_df['purchase_level'] = pd.qcut(user_df['avg_order_value'], 5, labels=False)
# 商品价格等级
item_df['price_level'] = pd.qcut(item_df['price'], 5, labels=False)
# 交叉特征
cross_feat = pd.merge(user_df[['user_id', 'purchase_level']],
item_df[['item_id', 'price_level']],
how='cross')
cross_feat['price_match'] = (cross_feat['purchase_level'] - cross_feat['price_level']).abs()
return cross_feat
2.3 特征选择:去掉"变质食材"的过程
不是所有特征都对模型有帮助。我们通过以下方法筛选优质特征:
-
特征重要性分析:
- 基于树模型的特征重要性排序
- 使用SHAP值分析特征贡献度
-
相关性分析:
- 去除与其他特征相关性>0.9的特征
- 检测特征与目标变量的非线性关系
-
业务逻辑验证:
- 每个特征必须有可解释的业务含义
- 拒绝"黑箱"特征(即使效果好但无法解释)
踩坑记录:曾有一个特征组合在离线评估中AUC提升显著,上线后却导致推荐多样性下降。后来发现是特征泄露了未来信息。现在我们会严格检查特征的时间因果关系。
3. 大数据环境下的特征工程优化
3.1 分布式特征计算架构
当用户行为数据达到PB级时,我们采用这样的技术栈:
code复制原始日志 → Flink实时计算 → 特征仓库(Redis/HBase) → 特征服务(在线/近线)
关键优化点:
- 实时特征更新:用户最新行为在5分钟内影响推荐结果
- 特征版本管理:像管理代码一样管理特征定义
- 计算资源分配:高频特征实时计算,低频特征批量计算
3.2 特征存储与检索优化
我们对比过多种存储方案后的选择:
| 存储系统 | 适用场景 | 优缺点 |
|---|---|---|
| Redis | 实时特征 | 低延迟但成本高 |
| HBase | 用户画像 | 适合稀疏大数据量 |
| Parquet | 离线特征 | 高压缩比适合分析 |
python复制# 特征存储服务示例
class FeatureStore:
def __init__(self):
self.real_time = RedisClient()
self.offline = HBaseClient()
def get_features(self, user_id, feature_names):
# 优先从实时缓存获取
features = self.real_time.mget(user_id, feature_names)
if None in features.values():
# 回退到离线存储
missing = [k for k,v in features.items() if v is None]
offline_feats = self.offline.get(user_id, missing)
features.update(offline_feats)
return features
3.3 特征监控与迭代
建立特征质量监控体系至关重要:
-
数据质量监控:
- 特征缺失率报警
- 数值分布漂移检测
-
效果监控:
- 新特征上线A/B测试
- 特征重要性变化趋势
-
迭代机制:
- 每月特征回顾会议
- 自动化特征实验平台
4. 典型问题与解决方案
4.1 冷启动问题
解决方案矩阵:
| 场景 | 策略 | 实现示例 |
|---|---|---|
| 新用户 | 强化上下文特征 | 地理位置、设备信息、访问渠道 |
| 新商品 | 内容特征迁移 | 类目相似商品的特征平均 |
| 新场景 | 跨域特征共享 | 复用其他业务线的用户画像 |
4.2 特征维度爆炸
我们采用的降维方法:
-
业务导向降维:
- 类目层级上卷(三级类目→二级类目)
- 连续值分桶(年龄分段、价格区间)
-
算法降维:
- 重要特征筛选(基于L1正则化)
- 特征嵌入(通过AutoEncoder学习低维表示)
-
工程优化:
- 稀疏特征哈希
- 特征分片加载
4.3 线上线下一致性
保证离线训练和在线服务的特征一致性:
-
特征管道统一:
- 使用相同的特征计算代码库
- 特征版本快照机制
-
一致性检查:
- 在线请求特征值抽样验证
- 离线特征统计与线上监控对比
-
容错机制:
- 特征缺失时的降级方案
- 特征值异常时的截断处理
5. 实战:电商推荐系统特征工程案例
5.1 数据准备
我们使用的数据集包含:
- 用户基础信息表(200万用户)
- 商品属性表(50万SKU)
- 行为日志(日均1亿条)
python复制# 数据加载与预处理
def load_data():
user_df = spark.read.parquet("hdfs://user_data/*.parquet")
item_df = spark.read.parquet("hdfs://item_data/*.parquet")
log_df = spark.read.parquet("hdfs://behavior_log/%Y-%m-%d/")
# 时间窗口处理
log_df = log_df.withColumn("hour", hour(col("timestamp")))
return user_df, item_df, log_df
5.2 特征流水线实现
我们的特征工程流水线包含以下阶段:
-
基础特征提取:
- 用户统计特征(点击次数、购买转化率)
- 商品热度特征(CTR、购买人数)
-
高阶特征构造:
- 用户-商品交叉特征
- 序列建模特征(通过Transformer编码行为序列)
-
特征选择:
- 基于XGBoost的特征重要性筛选
- 去除方差过小的特征
python复制# 使用FeatureTools自动特征生成
import featuretools as ft
es = ft.EntitySet()
es = es.entity_from_dataframe(
entity_id="users",
dataframe=user_df,
index="user_id"
)
features, defs = ft.dfs(
entityset=es,
target_entity="users",
agg_primitives=["count", "avg_time_between"],
trans_primitives=["hour", "day_of_week"]
)
5.3 效果评估与迭代
我们建立的评估体系包含三个层次:
-
离线指标:
- AUC、NDCG@10
- 覆盖率、新颖性
-
在线指标:
- 点击率、转化率
- 用户停留时长
-
业务指标:
- GMV贡献度
- 用户留存率
经过3个月的特征优化迭代,关键指标变化:
| 指标 | 优化前 | 优化后 | 提升幅度 |
|---|---|---|---|
| CTR | 4.2% | 6.1% | +45% |
| 转化率 | 1.8% | 2.5% | +39% |
| 用户留存 | 28% | 34% | +21% |
在特征工程实践中,我发现最容易被忽视的是特征的可解释性。曾经为了提升模型效果,我们引入了一些复杂的交叉特征,虽然离线指标提升了,但在业务分析时却无法解释推荐逻辑。现在我坚持一个原则:每个进入模型的特征,产品经理都能理解它的业务含义。
