4. 数据准备与预处理:交易数据清洗、客户信息标准化、缺失值处理、异常值检测
在反洗钱监测模型的生命周期中,数据准备与预处理是决定模型成败的基石。原始交易数据与客户信息通常来自多个异构系统,包含大量噪声、重复、缺失与异常。本章聚焦于将原始数据转化为高质量、标准化、可供模型直接使用的特征矩阵,涵盖四大核心环节:交易数据清洗、客户信息标准化、缺失值处理与异常值检测。
4.1 交易数据清洗
交易数据清洗的目标是消除因系统故障、人工录入错误或接口传输问题导致的脏数据。常见清洗任务包括:
- 去重:基于交易流水号、交易时间、金额、对手方等关键字段的组合,识别并移除完全重复或高度相似的记录。
- 格式统一:将日期时间字段统一为
YYYY-MM-DD HH:MM:SS格式;金额字段统一为两位小数,并去除货币符号与千分位分隔符。 - 逻辑校验:剔除交易时间早于开户时间、交易金额为负数或零(除特定冲正交易外)、交易币种与账户币种不匹配等逻辑矛盾记录。
- 字段拆分与合并:将“交易附言”中的结构化信息(如对手方账号、用途代码)拆分至独立字段;将分散在多张表中的交易关联信息合并至宽表。
实践要点:清洗规则应记录在数据质量规则库中,每次清洗后生成数据质量报告,统计清洗记录数、清洗原因分布,便于后续审计与规则迭代。
4.2 客户信息标准化
客户信息标准化旨在将来自不同业务系统(如核心银行、信用卡、财富管理)的客户数据映射到统一的数据模型,消除实体歧义。标准化流程通常包括:
- 身份标识统一:以客户唯一标识(如身份证号、统一社会信用代码)为主键,合并多系统客户档案。
- 名称清洗:去除全角/半角混乱、多余空格、特殊符号;对个人客户统一姓名大小写格式;对机构客户统一名称缩写规则。
- 地址与联系方式标准化:将地址拆分为省、市、区、详细地址;手机号统一为11位数字,去除国家代码前缀。
- 风险等级映射:将各系统不同的风险等级编码(如“高/中/低”、“1/2/3”、“A/B/C”)映射为统一的风险等级标签。
| 字段 | 原始格式示例 | 标准化后格式 |
|---|---|---|
| 客户姓名 | 张三 (含空格) | 张三 |
| 身份证号 | 110101199001011234 | 110101199001011234 |
| 手机号 | +86-13800138000 | 13800138000 |
| 风险等级 | High | 高风险 |
4.3 缺失值处理
缺失值在反洗钱数据中普遍存在,处理策略需结合字段的业务含义与缺失机制。常用方法包括:
- 删除:当缺失比例极低(<1%)且为随机缺失时,直接删除缺失记录;当关键字段(如交易对手方)缺失导致无法建模时,整条记录删除。
- 填充:
- 统计填充:连续变量使用均值、中位数填充;分类变量使用众数填充。
- 业务填充:如“交易渠道”缺失,可根据交易时间、金额、设备指纹等推断为“线上”或“柜面”。
- 模型填充:使用KNN、回归或随机森林预测缺失值,适用于缺失比例较高(5%-20%)且字段间相关性较强的场景。
- 标记:将缺失作为一种独立状态,新增“是否缺失”标志位,保留缺失信息对模型的可解释性。
注意:在反洗钱场景中,部分字段的缺失本身可能具有异常含义(如“职业”字段缺失可能暗示客户信息不完整),建议优先采用标记法或模型填充法,避免直接删除导致信息损失。
4.4 异常值检测
异常值检测用于识别与正常交易模式显著偏离的数据点,这些点可能是欺诈、洗钱行为或数据录入错误的信号。检测方法分为统计方法与机器学习方法两大类:
| 方法类别 | 具体方法 | 适用场景 |
|---|---|---|
| 统计方法 | Z-Score、IQR(四分位距) | 单变量、近似正态分布的数据 |
| 距离方法 | KNN、LOF(局部异常因子) | 多变量、密度分布不均的数据 |
| 聚类方法 | DBSCAN、孤立森林 | 高维数据、无标签场景 |
| 时间序列方法 | 移动平均、STL分解 | 交易频率、金额的时间序列数据 |
以下SVG图展示了从原始数据到预处理后数据的完整流程,以及各环节之间的依赖关系:
4.5 异常值处理策略
检测到异常值后,需根据业务场景选择处理方式:
- 修正:对于因系统故障导致的明显错误(如金额多一个零),根据业务规则或历史均值修正。
- 截尾:对极端值进行截尾处理(如将超过99.9%分位数的值替换为该分位数),减少对模型的影响。
- 保留并标记:对于疑似洗钱行为的异常交易,保留原始值并新增“异常标志”字段,供模型学习异常模式。
- 单独建模:将异常值单独提取,构建专门的异常交易预警模型,与主模型并行运行。
最佳实践:建议建立异常值处理日志,记录每条异常记录的检测方法、处理方式、处理前后值及审批人,确保数据处理的透明性与可追溯性。
以下SVG图对比了三种常见异常值检测方法在二维空间中的检测效果差异:
4.6 数据预处理代码示例
以下Python代码片段展示了使用Pandas进行交易数据清洗与缺失值处理的典型流程:
import pandas as pd
import numpy as np
# 加载原始交易数据
df = pd.read_csv('transactions_raw.csv')
# 1. 交易数据清洗
# 去重
df = df.drop_duplicates(subset=['txn_id', 'txn_time', 'amount', 'counterparty'])
# 格式统一
df['txn_time'] = pd.to_datetime(df['txn_time'], format='%Y-%m-%d %H:%M:%S')
df['amount'] = df['amount'].str.replace(',', '').str.replace('¥', '').astype(float)
# 逻辑校验:剔除金额为负或零的记录(冲正交易除外)
df = df[~((df['amount'] <= 0) & (df['txn_type'] != 'REVERSAL'))]
# 2. 缺失值处理
# 统计缺失比例
missing_ratio = df.isnull().mean()
# 对'channel'字段使用众数填充
df['channel'].fillna(df['channel'].mode()[0], inplace=True)
# 对'customer_occupation'字段新增缺失标志
df['occupation_missing'] = df['customer_occupation'].isnull().astype(int)
df['customer_occupation'].fillna('未知', inplace=True)
# 3. 异常值检测(IQR方法)
Q1 = df['amount'].quantile(0.25)
Q3 = df['amount'].quantile(0.75)
IQR = Q3 - Q1
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR
# 标记异常交易
df['amount_anomaly'] = ((df['amount'] < lower_bound) | (df['amount'] > upper_bound)).astype(int)
print(f"预处理完成,最终数据量: {len(df)} 条")
print(f"异常交易占比: {df['amount_anomaly'].mean():.2%}")
4.7 数据质量评估指标
完成预处理后,需从以下维度评估数据质量,确保数据满足建模要求:
| 维度 | 指标 | 目标阈值 |
|---|---|---|
| 完整性 | 各字段缺失率 | < 5% |
| 唯一性 | 重复记录占比 | < 1% |
| 准确性 | 逻辑校验通过率 | > 99% |
| 一致性 | 字段格式统一率 | 100% |
| 时效性 | 数据延迟时间 | < 24小时 |
关键提醒:数据预处理不是一次性工作。在模型迭代过程中,每次新增数据源或调整业务规则时,都应重新执行预处理流程,并对比数据质量指标的变化。建议将预处理逻辑封装为可复用的ETL管道,配合版本控制,确保模型训练与线上评分使用相同的数据处理逻辑。