第三章:反洗钱数据特征工程

各位同学,今天我们来聊聊反洗钱建模中最“脏”也最“关键”的一步——特征工程。说实话,我在这个领域摸爬滚打这么多年,见过太多模型因为特征没做好而翻车的案例。你想想看,数据质量不行,再牛的深度学习模型也是白搭。

核心观点:特征工程决定了模型效果的上限,而模型算法只是在逼近这个上限。我个人习惯把70%的时间花在特征工程上,剩下的30%才给模型调参。

反洗钱特征工程 数据清洗 特征构建 标签生成策略 数据不平衡处理 缺失值处理 异常值检测 金额特征 频率特征 地域特征 时间特征 监督/半监督/无监督 时间窗口标签 过采样 欠采样 代价敏感学习 反洗钱特征工程四大核心模块及其子任务

3.1 交易数据清洗——别让脏数据毁了你的模型

数据清洗这事儿,听起来简单,做起来全是坑。我记得刚入行那会儿,接手一个银行的反洗钱项目,数据量大概有5000万条交易记录。我心想,这不就是去去空值、删删重复嘛,结果一跑出来,模型AUC只有0.52,跟抛硬币差不多。

后来排查才发现,问题出在数据清洗上。具体来说,有这几个地方特别容易翻车:

  • 缺失值处理:交易对手信息、交易渠道这些字段,缺失率可能高达30%以上。我建议不要直接删掉,而是根据业务逻辑填充。比如交易对手为空,可以标记为“未知账户”或填充为“0”。
  • 异常值检测:单笔交易金额动辄几个亿,这正常吗?不一定。有些是机构间的大额调拨,有些纯粹是数据录入错误。我习惯用IQR(四分位距)方法先粗筛,再结合业务规则人工复核。
  • 重复交易:同一个交易ID出现多次,可能是系统重试导致的。我曾经遇到过一个案例,某笔交易被重复记录了17次,直接导致该账户的“交易频率”特征暴涨。

我的小技巧:清洗完成后,一定要做一次“数据质量报告”。统计每个字段的缺失率、异常值比例、重复率。这个报告能帮你快速定位问题,也方便跟业务方沟通。

3.2 特征构建——从原始数据中挖出金子

特征构建是反洗钱建模的核心。说白了,就是把原始的交易流水,转化成能反映洗钱行为的数值特征。我一般从四个维度入手:金额、频率、地域、时间。

3.2.1 金额特征

金额是最直观的特征。但光用原始金额是不够的,需要做一些变换:

  • 对数变换:金额分布通常呈长尾分布,取log后更接近正态分布,模型更容易学习。
  • 统计量特征:过去7天、30天的平均交易金额、最大金额、最小金额、标准差。这些能反映账户的资金流动模式。
  • 整额交易占比:洗钱分子喜欢用整数金额(比如10万、50万)来规避检测。计算一下账户中整额交易的比例,这个特征在实战中非常有效。
# 金额特征构建示例
import pandas as pd
import numpy as np

def build_amount_features(df):
    # 对数变换
    df['amount_log'] = np.log1p(df['amount'])
    
    # 过去30天统计量
    df['avg_amount_30d'] = df.groupby('account_id')['amount'].transform(
        lambda x: x.rolling(30).mean()
    )
    df['std_amount_30d'] = df.groupby('account_id')['amount'].transform(
        lambda x: x.rolling(30).std()
    )
    
    # 整额交易占比(金额为10000的整数倍)
    df['is_round_amount'] = (df['amount'] % 10000 == 0).astype(int)
    df['round_amount_ratio'] = df.groupby('account_id')['is_round_amount'].transform('mean')
    
    return df

3.2.2 频率特征

频率特征反映的是交易活跃度。洗钱账户通常有“快进快出”的特点,交易频率会异常高。

  • 交易次数:过去1天、7天、30天内的交易笔数。
  • 交易间隔:相邻两笔交易的时间差。间隔越短,越可疑。
  • 夜间交易占比:凌晨0点到5点的交易占比。正常用户很少在这个时间段频繁交易。

注意:频率特征容易受到“僵尸账户”的干扰。有些账户长期不用,突然活跃起来,这本身就是一个强信号。我建议把“休眠期”也作为一个特征加入模型。

3.2.3 地域特征

地域特征在跨境洗钱场景中特别重要。我做过一个项目,发现大量可疑交易都指向同一个离岸金融中心。

  • 高风险地区交易占比:根据FATF(反洗钱金融行动特别工作组)名单,标记高风险国家/地区,计算交易占比。
  • 地域分散度:交易对手涉及的不同城市/国家数量。分散度越高,越可疑。
  • 地理距离:交易双方的地理距离。比如一个上海的小商户,频繁跟新疆的账户交易,这就不太正常。

3.2.4 时间特征

时间特征能捕捉交易的时间规律。洗钱分子往往会避开正常的工作时间。

  • 小时特征:交易发生在几点?可以分桶处理(0-6点、6-12点、12-18点、18-24点)。
  • 星期特征:周末交易占比。正常企业很少在周末进行大额交易。
  • 节假日特征:节假日前后往往是洗钱高发期。我习惯把“距离最近节假日的天数”作为一个特征。

3.3 标签生成策略——没有标签怎么办?

反洗钱领域最大的痛点是什么?标签稀缺。真正被确认的洗钱案例少之又少,正负样本比例可能达到1:10000甚至更低。

我常用的标签生成策略有三种:

策略类型 方法描述 适用场景 优缺点
监督学习 使用已确认的可疑交易作为正样本 有历史案例积累的机构 准确率高,但样本量少
半监督学习 用规则引擎生成“疑似标签”,再人工复核 规则明确但人力有限 样本量扩大,但噪声增加
无监督学习 用聚类或异常检测发现离群点 完全没有标签的新业务 可以发现新模式,但解释性差

实战经验:我个人最推荐“半监督+人工复核”的方式。先用规则引擎(比如单笔超过100万、频繁换卡等)生成一批候选标签,然后让风控专家审核。这样既能保证标签质量,又能快速扩大样本量。

另外,时间窗口标签也很重要。比如“交易发生后30天内是否被举报”,这个窗口期设置得太短会漏掉案例,太长又会引入噪声。我一般会设置7天、30天、90天三个窗口,分别训练模型,然后做模型融合。

3.4 数据不平衡处理——让模型关注少数派

数据不平衡是反洗钱建模的“老熟人”了。正样本可能只有0.1%,直接训练的话,模型会学成一个“永远预测正常”的废物。

我常用的处理方法有这几种:

  • 过采样(SMOTE):合成少数类样本。但要注意,SMOTE在反洗钱场景中容易生成“不真实”的样本。我曾经试过,生成的样本在业务上完全不合理,比如一个从未出过国的用户,突然有了跨境交易记录。
  • 欠采样:随机删除多数类样本。简单粗暴,但会丢失大量信息。我建议用“NearMiss”方法,只保留离正样本最近的负样本。
  • 代价敏感学习:给正样本更高的权重。比如设置class_weight='balanced',让模型更关注少数类。这个方法在深度学习框架中很容易实现。
  • 异常检测方法:把反洗钱问题转化为异常检测问题。用Isolation Forest、AutoEncoder等模型,直接检测离群点。
# 代价敏感学习示例(PyTorch)
import torch.nn as nn

# 计算类别权重
pos_weight = torch.tensor([100.0])  # 正样本权重设为负样本的100倍
criterion = nn.BCEWithLogitsLoss(pos_weight=pos_weight)

# 训练时,模型会自动给正样本更高的惩罚

避坑指南:我曾经犯过一个错误——在测试集上也做了过采样。结果模型在测试集上表现很好,上线后直接崩了。记住:永远只在训练集上做数据不平衡处理,测试集要保持原始分布

好了,关于反洗钱数据特征工程,核心内容就是这些。数据清洗、特征构建、标签生成、不平衡处理,这四个环节环环相扣,任何一个环节出问题,模型效果都会大打折扣。希望这些经验能帮你少走一些弯路。


专注资料整理