3. 特征工程基础:特征分类、构造方法与在线服务架构
特征工程是A/B测试效果评估的基石。原始数据往往包含噪声、缺失值和不一致的格式,直接用于实验分析会导致偏差或统计功效下降。本章系统梳理特征分类体系、构造方法以及支撑在线回放的服务架构,为后续特征回放实验打下扎实基础。
3.1 特征分类:数值、类别与序列
根据数据结构和业务含义,特征通常分为三大类。不同类别在预处理、存储和回放策略上存在显著差异。
| 特征类型 | 典型示例 | 存储格式 | 回放注意事项 |
|---|---|---|---|
| 数值特征 | 用户年龄、商品价格、点击次数 | Float / Int | 需关注异常值截断、缺失值填充(均值/中位数) |
| 类别特征 | 城市、设备类型、用户等级 | String / Enum | 低基数用One-Hot,高基数用Target Encoding或Embedding |
| 序列特征 | 用户浏览路径、行为时间戳序列 | Array / List | 需固定长度(Padding/Truncation),保留时序依赖 |
实践建议:在特征回放A/B测试中,类别特征的高基数问题容易被忽视。若直接对城市ID(数千个取值)做One-Hot,会导致特征维度爆炸,增加回放延迟。建议优先使用Target Encoding或预训练Embedding降维。
3.2 特征构造方法
特征构造是从原始数据中提取信息增益的过程。以下列出四种在实验评估中高频使用的方法,并给出适用场景。
- 统计聚合:对用户历史行为做count、sum、mean、std、max/min。例如“过去7天购买次数”、“平均浏览时长”。适用于数值特征和序列特征。
- 时间窗口特征:固定时间窗口(1h/1d/7d)内的行为统计,支持滑动窗口。常用于捕捉用户短期兴趣变化。
- 交叉组合:将两个或多个类别特征组合成新特征。例如“城市+设备类型”组合为新的类别特征,可捕获交互效应。
- 序列模式提取:从行为序列中提取转移概率、频繁子序列、最后N步动作。适用于推荐、搜索等强时序场景。
关键原则:特征构造必须避免数据泄露。在A/B测试回放中,构造特征时只能使用实验开始时间点之前的历史数据,不能混入未来信息。例如计算“用户是否点击”时,不能使用点击后的行为数据。
3.3 特征存储与在线服务架构
特征回放A/B测试要求特征在实验期间能够被低延迟、高并发地读取。传统的离线Hive/Spark表无法满足在线要求,因此需要构建专用的特征存储层。
3.3.1 存储选型对比
| 存储方案 | 读写延迟 | 一致性模型 | 适用场景 |
|---|---|---|---|
| Redis / Memcached | < 5ms | 最终一致性 | 高并发实时特征读取 |
| HBase / Cassandra | 10-50ms | 强一致性(行级) | 大规模特征存储,支持宽表 |
| MySQL / PostgreSQL | 5-20ms | 强一致性 | 小规模特征,需要事务支持 |
| Embedding Server (Faiss/Annoy) | 10-100ms | 最终一致性 | 向量特征近邻检索 |
3.3.2 在线特征服务架构
一个典型的在线特征服务(Feature Store)包含三个核心层:特征生产层、存储层、服务层。特征回放实验时,服务层需要支持按时间戳回滚到历史特征版本。
- 特征生产层:离线批处理(Spark/Flink)生成全量特征,实时流处理(Flink/Kafka)更新增量特征。
- 特征存储层:双存储设计——热存储(Redis)存放最新特征,冷存储(HBase)存放历史快照。
- 特征服务层:提供统一的gRPC/REST API,支持“按实体ID+时间戳”查询历史特征,用于回放实验。
回放实验关键要求:特征服务必须支持时间旅行查询。即给定用户ID和实验开始时间T0,能够返回T0时刻该用户的所有特征快照,而非当前最新值。否则回放实验会混入未来信息,导致效果评估虚高。
3.4 特征回放实验中的工程要点
在A/B测试场景下,特征回放与常规在线推理存在本质区别。以下列出三个必须关注的工程要点:
- 特征对齐:实验组和对照组必须使用同一时间点的特征快照,不能出现“实验组用T0特征,对照组用T1特征”的情况。
- 特征版本冻结:实验开始后,特征构造逻辑不能变更。若需更新特征,应启动新的实验,避免污染正在运行的实验。
- 回放性能:回放实验通常需要批量处理百万级用户,特征服务应支持批量查询(Batch Get),避免逐条请求导致延迟过高。
代码示例:特征回放批量查询接口(伪代码)
# 批量查询特征快照
def batch_get_features(entity_ids: List[str], timestamp: int) -> Dict[str, Feature]:
# 1. 优先从Redis缓存查询
cached = redis_cache.batch_get(entity_ids)
# 2. 未命中部分从HBase历史快照补全
miss_ids = [eid for eid in entity_ids if eid not in cached]
if miss_ids:
history = hbase_store.batch_get(miss_ids, timestamp)
# 3. 回填缓存(设置TTL避免过期)
redis_cache.batch_set(history, ttl=3600)
cached.update(history)
return cached
通过上述特征分类、构造方法和在线架构的配合,特征回放A/B测试能够在保证数据一致性的前提下,高效评估模型或策略的离线效果,为线上决策提供可靠依据。