4. 特征工程入门:特征分类与构造
特征工程是数据产品从“可用”走向“好用”的关键环节。在分群评分沙盘中,原始数据往往无法直接用于模型训练,必须经过分类识别、清洗转换和衍生构造,才能成为真正有预测能力的特征。本章从特征分类出发,系统讲解数值型、类别型、时序型特征的处理逻辑,并给出常用的特征构造与衍生方法。
4.1 特征三大分类
根据数据本身的测量尺度和业务含义,特征通常分为三类:数值型、类别型和时序型。不同类型对应不同的预处理和编码策略。
| 特征类型 | 定义 | 典型示例 | 常见问题 |
|---|---|---|---|
| 数值型 | 连续或离散的定量测量值,可进行算术运算 | 年龄、收入、交易金额、点击次数 | 量纲差异、异常值、长尾分布 |
| 类别型 | 有限个离散取值,表示所属分组或标签 | 性别、城市、职业、会员等级 | 基数过高、顺序编码误导、缺失类别 |
| 时序型 | 带有时间顺序的观测值,依赖前后关系 | 登录时间、购买日期、行为序列 | 时间窗口选择、周期性、非对齐采样 |
实践建议:在分群评分场景中,数值型特征通常直接进入距离计算或树模型分裂;类别型特征需要先做编码(如独热、目标编码);时序型特征则必须提取统计量(如最近30天均值)后才能参与建模。
4.2 特征构造与衍生方法
特征构造是从原始数据中主动创建新特征的过程,目的是暴露数据中隐藏的模式。以下列出三类最常用的构造方法。
4.2.1 数值型特征衍生
- 多项式组合:对两个或多个数值特征做乘、除、平方、交叉乘积,例如
收入 / 年龄、消费金额²。 - 分箱离散化:将连续值按等距、等频或业务阈值切分为有序类别,例如年龄分箱为
[0-18, 19-35, 36-55, 56+]。 - 统计聚合:在分组内计算均值、标准差、最大值、最小值、变异系数等,例如“用户过去7天平均订单金额”。
- 比率与占比:构造分子/分母形式的指标,如“信用卡使用率 = 信用卡消费 / 总消费”。
4.2.2 类别型特征编码
| 编码方法 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| 独热编码 | 低基数类别(< 20 个取值) | 无顺序假设,模型可解释 | 维度爆炸,稀疏矩阵 |
| 标签编码 | 有序类别(如等级、学历) | 保留顺序信息,节省内存 | 误导模型认为数值有等差关系 |
| 目标编码 | 高基数类别(城市、商品ID) | 压缩维度,直接关联目标 | 易过拟合,需交叉验证平滑 |
| 频次编码 | 类别分布极不均匀 | 简单稳定,反映流行度 | 丢失类别语义 |
4.2.3 时序型特征提取
- 滑动窗口统计:在固定时间窗口内计算均值、总和、趋势斜率,例如“最近30天登录天数”。
- 时间戳分解:从日期时间中提取年、月、日、星期几、是否为节假日、是否为工作日。
- 间隔与周期:计算相邻事件的时间间隔、距当前时间的距离、周期性编码(如正弦/余弦变换)。
- 序列聚合:对行为序列做计数、去重计数、最长连续天数、模式匹配等。
案例:在信用卡评分沙盘中,原始数据只有“交易时间”和“交易金额”。通过时序特征衍生,可以构造出“近7天交易笔数”“近30天交易总额”“交易时间间隔标准差”“周末交易占比”等强预测特征,显著提升分群区分度。
4.3 特征构造流程总览
下图展示了从原始数据到可用特征集的完整构造流程,包含分类识别、清洗转换、衍生构造和筛选评估四个阶段。
4.4 实战:从原始交易表构造评分特征
以下代码演示如何从一张原始交易记录表出发,通过特征工程构造出可用于分群评分的特征集。示例使用 Python 风格伪代码,核心逻辑可直接迁移到 Spark、SQL 或 Pandas 环境。
# 原始数据:交易记录表 transactions
# 字段:user_id, trans_date, trans_amount, merchant_type
# 1. 数值型特征衍生
df['amount_log'] = np.log1p(df['trans_amount']) # 对数变换
df['amount_per_day'] = df['trans_amount'] / df['days_since_reg'] # 比率特征
df['amount_bin'] = pd.cut(df['trans_amount'], bins=[0,100,500,2000,1e6], labels=['低','中','高','超高'])
# 2. 类别型特征编码(目标编码示例)
target_mean = df.groupby('merchant_type')['target'].mean()
df['merchant_target_enc'] = df['merchant_type'].map(target_mean)
# 3. 时序型特征提取
df['trans_year'] = df['trans_date'].dt.year
df['trans_month'] = df['trans_date'].dt.month
df['trans_weekday'] = df['trans_date'].dt.weekday
# 滑动窗口:每个用户最近30天交易笔数
df['last30d_count'] = df.sort_values('trans_date') \
.groupby('user_id')['trans_date'] \
.rolling(window='30D', on='trans_date') \
.count() \
.reset_index(level=0, drop=True)
# 4. 聚合特征:用户级汇总
user_features = df.groupby('user_id').agg(
total_amount=('trans_amount', 'sum'),
avg_amount=('trans_amount', 'mean'),
trans_count=('trans_date', 'count'),
unique_merchant=('merchant_type', 'nunique'),
last_trans_days=('trans_date', lambda x: (pd.Timestamp.today() - x.max()).days)
).reset_index()
避坑提醒:特征构造时务必注意数据泄露问题。滑动窗口统计只能使用历史数据,不能包含未来信息;目标编码必须在训练集内进行交叉验证平滑,避免直接使用全量目标均值。
4.5 特征构造的常见陷阱与应对
| 陷阱 | 表现 | 应对策略 |
|---|---|---|
| 数据泄露 | 特征使用了未来信息,模型在线上失效 | 严格按时间切分训练/验证集;滑动窗口只使用历史窗口 |
| 维度灾难 | 独热编码后特征数量暴增,模型过拟合 | 使用目标编码、嵌入或特征选择降维 |
| 缺失值传播 | 衍生特征因原始缺失而大量为空 | 提前填充或标记缺失;使用树模型天然处理缺失 |
| 特征冗余 | 高度相关的特征降低模型稳定性 | 计算相关性矩阵,保留代表性特征或做PCA |
核心原则:特征构造不是越多越好。在分群评分沙盘中,优先保证每个特征都有清晰的业务含义和可解释性,再通过交叉验证评估其增量贡献。一个干净、可解释的50维特征集,往往优于混乱的500维特征集。