4、用户画像与特征工程:基础属性特征、行为特征、关系网络特征、特征存储与实时计算

在流式决策链路中,用户画像与特征工程是连接原始数据与额度定价模型的桥梁。特征的质量直接决定了模型对风险与收益的刻画能力。本章从基础属性、行为轨迹、关系网络三个维度拆解特征体系,并深入探讨特征存储架构与实时计算方案。

4.1 特征体系三维度

信贷场景下的用户特征可归纳为三大类:基础属性特征(静态或低频变化)、行为特征(动态时序)、关系网络特征(社交与资金关联)。三者共同构成完整的用户画像。

特征维度 数据来源 更新频率 典型特征示例
基础属性 身份证、征信报告、运营商 月/季度 年龄、性别、学历、婚姻状况、居住稳定性、职业类别
行为特征 APP埋点、交易流水、还款记录 秒/分钟/天 登录频次、浏览时长、消费金额、还款逾期天数、额度使用率
关系网络 通讯录、转账记录、担保关系 天/周 联系人数量、二度关联逾期率、资金流入流出比、团伙标识
实战要点:基础属性特征在首次授信时权重最高,但随着用户行为数据积累,行为特征的预测能力会逐步超越基础属性。关系网络特征在反欺诈和团伙识别中不可替代,但在额度定价中需谨慎使用,避免群体歧视。

4.2 基础属性特征工程

基础属性特征通常来自用户授权数据或第三方数据源,处理重点在于缺失值填充、异常值清洗和分箱编码。

  • 缺失值处理:对于学历、职业等分类特征,使用“未知”作为独立类别;对于收入等连续特征,使用中位数或分位数填充。
  • 异常值截断:年龄超过100岁、收入为负值等明显错误数据,按业务逻辑截断或剔除。
  • 分箱与WOE编码:将连续特征(如年龄)按业务经验或卡方分箱离散化,再计算每个分箱的WOE(Weight of Evidence)值,用于逻辑回归等线性模型。
# 年龄分箱与WOE编码示例(Python伪代码)
import pandas as pd
import numpy as np

def age_woe_encoding(df, target_col='is_default'):
    # 按业务经验分箱
    bins = [0, 25, 35, 45, 55, 100]
    labels = ['18-25', '26-35', '36-45', '46-55', '56+']
    df['age_bin'] = pd.cut(df['age'], bins=bins, labels=labels)
    
    # 计算每个分箱的坏账率与WOE
    total_good = df[target_col].sum()
    total_bad = len(df) - total_good
    woe_dict = {}
    for bin_label in labels:
        bin_df = df[df['age_bin'] == bin_label]
        good = bin_df[target_col].sum()
        bad = len(bin_df) - good
        woe = np.log((bad / total_bad) / (good / total_good))
        woe_dict[bin_label] = woe
    return woe_dict

4.3 行为特征工程

行为特征是流式决策中最具时效性的信号。核心处理思路包括统计聚合、时序特征和比率特征。

  • 滑动窗口统计:过去7天/30天的登录次数、消费金额均值、最大单笔金额等。
  • 趋势特征:近3个月额度使用率的斜率、还款金额的环比变化。
  • 行为序列特征:用户从注册到首次借款的天数、浏览产品页面的路径长度。
实时计算提示:行为特征在流式场景中通常使用Flink或Spark Streaming进行滑动窗口聚合。窗口大小建议与决策频率匹配——额度调整场景常用7天和30天双窗口,既能捕捉短期波动,又能保留长期趋势。

4.4 关系网络特征工程

关系网络特征通过图算法提取用户的社会关系和资金往来模式。常用方法包括度中心性、PageRank和社区检测。

特征类型 计算方法 业务含义
入度/出度 统计用户被转账/向他人转账的次数 资金活跃度与依赖关系
二度关联逾期率 用户好友中逾期用户占比 风险传染可能性
PageRank值 迭代计算节点在图中的重要性 识别关键人物或资金枢纽
社区标签 Louvain/标签传播算法 团伙欺诈识别
合规红线:关系网络特征涉及用户通讯录和社交数据,必须获得用户明确授权。在额度定价模型中,不得直接使用“联系人数量”等敏感特征作为拒绝依据,建议仅用于辅助欺诈评分。

4.5 特征存储架构

特征存储需要同时满足在线低延迟读取和离线批量训练的需求。业界主流方案采用分层存储架构。

特征存储分层架构 实时特征层 Redis / Aerospike 毫秒级读取 TTL过期策略 近线特征层 HBase / Cassandra 秒级读取 小时级更新 离线特征层 Hive / Parquet 分钟级读取 天级全量更新 特征同步策略 离线层 → 近线层:每日凌晨T+1批量同步,覆盖全量用户画像。 近线层 → 实时层:增量推送,仅同步近24小时有行为变化的用户特征。 统一特征服务(Feature Store) 特征注册中心 | 版本管理 | 在线/离线一致性校验

4.6 实时特征计算方案

流式决策要求特征在用户请求到达时立即可用。实时计算方案通常基于事件驱动架构,核心组件包括消息队列、流计算引擎和特征存储。

  1. 事件采集:用户行为(点击、借款、还款)通过SDK上报至Kafka,每条事件携带用户ID、事件类型、时间戳。
  2. 流计算:Flink消费Kafka消息,按用户ID进行keyBy分组,在滑动窗口内计算聚合特征(如近7天借款次数)。
  3. 特征更新:计算结果写入Redis,设置TTL(如7天),同时异步写入HBase作为近线备份。
  4. 在线读取:决策引擎在收到额度请求时,通过Feature Store的API从Redis读取实时特征,若缺失则降级到HBase。
-- Flink SQL 实时特征计算示例
CREATE TABLE user_behavior (
  user_id STRING,
  event_type STRING,
  amount DOUBLE,
  event_time TIMESTAMP(3),
  WATERMARK FOR event_time AS event_time - INTERVAL '5' SECOND
) WITH (
  'connector' = 'kafka',
  'topic' = 'user_events',
  'properties.bootstrap.servers' = 'localhost:9092',
  'format' = 'json'
);

CREATE TABLE redis_sink (
  user_id STRING,
  loan_count_7d BIGINT,
  total_amount_7d DOUBLE,
  PRIMARY KEY (user_id) NOT ENFORCED
) WITH (
  'connector' = 'redis',
  'redis.mode' = 'single',
  'host' = 'localhost',
  'port' = '6379'
);

INSERT INTO redis_sink
SELECT
  user_id,
  COUNT(*) AS loan_count_7d,
  SUM(amount) AS total_amount_7d
FROM user_behavior
WHERE event_type = 'loan'
GROUP BY
  user_id,
  HOP(event_time, INTERVAL '1' MINUTE, INTERVAL '7' DAY);
性能优化建议:实时特征计算应避免大状态(如存储全量用户行为序列)。建议将窗口大小控制在30天以内,并使用RocksDB状态后端。对于需要长期趋势的特征(如6个月还款趋势),在离线层计算后同步到近线层,实时层仅做增量修正。

4.7 特征质量监控

特征工程上线后必须建立持续监控机制,防止数据漂移或特征失效导致模型退化。

监控维度 指标 告警阈值 处理措施
缺失率 特征缺失值占比 > 5% 检查上游数据源是否异常
分布漂移 PSI(群体稳定性指标) > 0.1 重新分箱或模型重训
实时延迟 特征写入到可读取的延迟 > 500ms 扩容Flink算子或优化Redis连接池
特征一致性 在线特征与离线特征差异 > 1% 检查特征计算逻辑是否一致
最佳实践:建议在特征存储层为每个特征打上版本标签(如 v1.2.3),并在模型推理时记录特征版本号。当特征逻辑变更时,可以快速回溯历史决策,定位模型效果变化的原因。