3. 特征工程基础:特征分类、特征衍生、特征存储格式
特征工程是风控模型从原始数据到有效预测能力的核心桥梁。在坏账率回测哨兵系统中,特征的质量直接决定哨兵能否在早期准确识别资产质量恶化信号。本章从特征分类、特征衍生、存储格式三个维度,建立特征工程的基础知识体系。
3.1 特征分类:从数据源到业务语义
风控场景中的特征可按数据来源、时间窗口、业务含义三个维度进行分类。不同分类方式对应不同的处理策略和存储要求。
| 分类维度 | 特征类型 | 典型示例 | 处理要点 |
|---|---|---|---|
| 数据来源 | 用户画像特征 | 年龄、性别、职业、学历 | 缺失值填充、异常值截断 |
| 行为序列特征 | 近30天登录次数、浏览时长 | 时间窗口聚合、趋势计算 | |
| 外部征信特征 | 征信查询次数、多头借贷数 | 数据对齐、时效性校验 | |
| 时间窗口 | 静态特征 | 注册时间、首笔借款金额 | 一次性计算,无需更新 |
| 动态特征 | 近7天逾期率、近3月平均额度 | 滑动窗口计算,需定期刷新 | |
| 业务含义 | 还款能力特征 | 收入负债比、可用额度 | 衍生逻辑复杂,需业务规则 |
| 还款意愿特征 | 历史逾期天数、催收响应率 | 需结合行为序列建模 |
实践建议:在哨兵系统中,动态特征和外部征信特征对坏账率波动的敏感度最高,建议优先构建这两类特征的自动化回测管道。
3.2 特征衍生:从原始数据到高价值信号
特征衍生是将原始字段转化为更具预测能力的特征变量的过程。在风控回测场景中,常用的衍生方法包括统计聚合、时间窗口计算、比率构造、交叉组合等。
3.2.1 常用衍生方法
- 统计聚合:对数值型字段计算均值、最大值、最小值、标准差、分位数等。
- 时间窗口计算:按固定时间窗口(7天、30天、90天)滑动计算统计量。
- 比率构造:两个相关字段的比值,如
逾期金额 / 总应还金额。 - 交叉组合:类别型字段的笛卡尔积,如
职业 × 城市等级。 - 排序编码:对类别型字段按目标变量均值排序后编码。
坏账率回测场景示例:原始字段包含
应还日期和实际还款日期,可衍生出逾期天数、是否逾期、逾期次数(近6个月)、最大逾期天数等特征,这些特征对坏账率预测的贡献度通常排名前10。
3.2.2 特征衍生代码示例
import pandas as pd
import numpy as np
# 原始数据示例
df = pd.DataFrame({
'user_id': [1001, 1002, 1003],
'due_date': pd.to_datetime(['2024-01-15', '2024-02-10', '2024-03-05']),
'repay_date': pd.to_datetime(['2024-01-14', '2024-02-15', '2024-03-10']),
'loan_amount': [5000, 10000, 8000],
'repay_amount': [5000, 10000, 7500]
})
# 特征衍生:逾期天数
df['overdue_days'] = (df['repay_date'] - df['due_date']).dt.days
df['overdue_days'] = df['overdue_days'].clip(lower=0)
# 特征衍生:还款率
df['repay_ratio'] = df['repay_amount'] / df['loan_amount']
# 特征衍生:是否逾期(二值化)
df['is_overdue'] = (df['overdue_days'] > 0).astype(int)
print(df[['user_id', 'overdue_days', 'repay_ratio', 'is_overdue']])
3.3 特征存储格式:Parquet vs Feather
在特征服务与回测系统中,特征数据的存储格式直接影响读写性能、存储成本和计算效率。Parquet 和 Feather 是当前最主流的两种列式存储格式,适用于不同场景。
3.3.1 格式对比
| 对比维度 | Parquet | Feather |
|---|---|---|
| 压缩率 | 高(支持 Snappy、Gzip、Zstd) | 低(仅支持 LZ4、Zstd) |
| 读写速度 | 读取快,写入较慢 | 读写均快(专为 Pandas 优化) |
| 跨语言支持 | 广泛(Spark、Hive、Presto 等) | 有限(主要 Python/R) |
| Schema 演进 | 支持(列添加/删除) | 不支持 |
| 适用场景 | 长期存储、数据湖、分布式计算 | 中间结果、快速迭代、单机分析 |
| 文件大小 | 小(压缩后通常为 CSV 的 20%-30%) | 中等(压缩后为 CSV 的 50%-70%) |
选型建议:在哨兵回测系统中,建议使用 Parquet 存储历史回测特征数据,利用其高压缩率和 Schema 演进能力降低存储成本;使用 Feather 存储中间计算特征,利用其高速读写特性加速迭代开发。
3.3.2 读写代码示例
import pandas as pd
import pyarrow.parquet as pq
import pyarrow.feather as ft
# 创建示例特征数据
feature_df = pd.DataFrame({
'user_id': range(1, 100001),
'overdue_days_30d': np.random.randint(0, 30, 100000),
'avg_loan_amount_90d': np.random.uniform(1000, 50000, 100000),
'repay_ratio_6m': np.random.uniform(0.5, 1.0, 100000),
'is_overdue_flag': np.random.choice([0, 1], 100000, p=[0.9, 0.1])
})
# 写入 Parquet(推荐用于长期存储)
feature_df.to_parquet('features_historical.parquet', compression='snappy')
# 写入 Feather(推荐用于中间结果)
ft.write_feather(feature_df, 'features_intermediate.feather')
# 读取验证
df_parquet = pd.read_parquet('features_historical.parquet')
df_feather = ft.read_feather('features_intermediate.feather')
print(f"Parquet 行数: {len(df_parquet)}, Feather 行数: {len(df_feather)}")
3.4 特征工程在哨兵系统中的位置
下图展示了特征工程在坏账率回测哨兵系统中的核心位置,以及特征分类、衍生、存储三个环节的协作关系。
3.5 特征存储选型决策流程
在实际项目中,特征存储格式的选择需要综合考虑数据量、访问模式、计算环境等因素。以下决策流程可帮助快速确定合适的存储方案。
实战经验:在哨兵回测系统中,建议将特征数据按时间分区存储(如
year=2024/month=01/),配合 Parquet 的谓词下推功能,可大幅提升回测时的数据读取效率。Feather 更适合在单次回测任务中作为中间缓存使用,避免重复计算。