4. 基础特征层构建:用户画像静态特征

基础特征层是风控特征分层架构中的第一层,也是最稳定的数据底座。本层主要从用户注册表、登录表等离线宽表中提取不随时间快速变化的静态属性,形成用户画像的核心标签。这些特征在模型生命周期内通常不会频繁更新,因此适合作为样本清洗和后续衍生特征计算的锚点。

核心原则:静态特征提取必须保证“一人一档”的原子性,避免因多源数据时间戳不一致导致画像污染。建议以用户注册时间作为时间基准,对齐所有静态字段。

4.1 静态特征域与数据源映射

在风控场景中,静态特征主要来源于用户注册信息与首次登录行为。下表列出了典型的数据源与对应特征域:

数据源 特征域 典型字段 提取方式
用户注册表 人口属性 年龄、性别、国籍、职业 直接映射或规则转换
用户注册表 渠道属性 注册渠道、邀请码、推广来源 字典编码或One-Hot
登录表 设备属性 首次登录设备型号、操作系统 取最早登录记录
登录表 网络属性 首次登录IP、运营商、地区 IP解析库关联
用户注册表 账户属性 注册时间、账户等级、实名状态 时间戳截断与状态枚举

4.2 基于Spark的静态特征提取流程

使用Spark SQL对用户注册表和登录表进行ETL,核心步骤包括:数据去重、时间对齐、字段转换、画像聚合。以下为典型实现代码:

// 1. 读取用户注册表,去重取最新记录
val regDF = spark.read.table("ods.user_register")
  .filter(col("dt") === maxPartition)
  .dropDuplicates("user_id")
  .select(
    col("user_id"),
    col("age"),
    col("gender"),
    col("register_channel"),
    col("register_time"),
    col("real_name_status")
  )

// 2. 读取登录表,取每个用户首次登录记录
val loginDF = spark.read.table("ods.user_login")
  .filter(col("dt") === maxPartition)
  .groupBy("user_id")
  .agg(
    first("device_model").as("first_device_model"),
    first("os_type").as("first_os_type"),
    first("login_ip").as("first_login_ip"),
    min("login_time").as("first_login_time")
  )

// 3. 关联IP解析库,提取地区与运营商
val ipGeoDF = spark.read.parquet("/data/dim/ip_geo")
val loginWithGeoDF = loginDF
  .join(ipGeoDF, loginDF("first_login_ip") === ipGeoDF("ip_start"), "left")
  .select(
    loginDF("user_id"),
    loginDF("first_device_model"),
    loginDF("first_os_type"),
    ipGeoDF("province").as("first_login_province"),
    ipGeoDF("isp").as("first_login_isp")
  )

// 4. 合并注册与登录特征,形成用户画像宽表
val userProfileDF = regDF
  .join(loginWithGeoDF, Seq("user_id"), "left")
  .withColumn("age_group", when(col("age") < 18, "underage")
    .when(col("age").between(18, 25), "young")
    .when(col("age").between(26, 40), "middle")
    .otherwise("senior"))
  .withColumn("register_hour", hour(col("register_time")))

// 5. 写入基础特征层
userProfileDF.write
  .mode("overwrite")
  .partitionBy("dt")
  .parquet("/data/feature_layer/base/user_profile/")
工程建议:年龄字段常存在异常值(如0、200),建议在提取时加入age BETWEEN 1 AND 120的过滤条件,并将异常值标记为-1,避免模型学习到错误分布。

4.3 静态特征质量校验规则

在写入特征层之前,必须执行质量校验。以下为推荐校验清单:

  • 完整性校验:用户画像表记录数不应低于注册表用户数的95%,缺失率超过5%的字段需标记并回填默认值。
  • 唯一性校验:user_id应为主键,不允许出现重复记录;若存在重复,取register_time最新的一条。
  • 值域校验:性别字段仅允许0/1/2(未知/男/女);注册渠道需在预定义字典内;年龄需在1-120之间。
  • 时间一致性校验:first_login_time不应早于register_time,若出现则取register_time作为首次登录时间。

4.4 用户画像静态特征分层架构

下图展示了从原始数据源到基础特征层的完整分层架构,以及各层之间的数据流向:

用户画像静态特征分层架构图 用户画像静态特征分层架构 ODS 用户注册表 ODS 用户登录表 DIM IP地理库 Spark ETL 处理 去重 → 时间对齐 → 字段转换 → IP解析 → 画像聚合 质量校验 完整性 | 唯一性 | 值域 | 时间一致性 基础特征层:用户画像宽表 说明:静态特征提取以用户注册时间为基准,首次登录信息通过取最早记录保证一致性

4.5 静态特征在样本清洗中的应用

基础特征层构建完成后,可直接用于样本清洗阶段的异常样本过滤与样本分层:

  • 年龄异常过滤:将年龄为0或大于120的用户标记为“年龄异常”,在样本清洗时剔除或降权。
  • 渠道黑名单过滤:若注册渠道属于已知作弊渠道(如批量注册工具),直接剔除该用户所有样本。
  • 地域冷启动分层:对于首次登录IP归属地为高风险地区的用户,在样本分层时划入“高关注”组,单独训练风控模型。
  • 设备指纹去重:若多个用户共享同一首次登录设备型号且注册时间接近,判定为团伙注册,清洗时合并为单一样本。
避坑提示:静态特征一旦写入基础特征层,不应频繁修改。若业务需要更新(如用户修改实名信息),必须通过增量更新方式写入,并保留历史版本快照,避免破坏样本时间序列的一致性。

4.6 静态特征存储与分区策略

为提升下游查询效率,建议采用以下存储与分区方案:

存储格式 压缩方式 分区字段 分桶字段 更新频率
Parquet Snappy dt(天分区) user_id(128桶) 每日全量覆盖
Parquet Zstd dt + register_channel user_id(256桶) 每日增量合并

推荐使用每日全量覆盖策略,因为静态特征数据量较小(通常为千万级),全量写入可避免增量合并带来的数据一致性问题。若用户量超过10亿,可切换为增量合并模式,但需额外维护变更日志表。