4. 原始特征构建:基于交易金额、频率、对手方、地理位置、时间模式的原始特征设计
原始特征构建是反洗钱特征工程的起点。直接从交易流水、客户信息、渠道日志中提取的未加工特征,构成了后续衍生特征、聚合特征和模型输入的基础。本章围绕五个核心维度——交易金额、交易频率、对手方、地理位置和时间模式——系统讲解原始特征的设计原则与提取方法。
核心原则:原始特征应保持“最小加工、最大信息”原则。避免在原始层做过多聚合或变换,保留数据的原始粒度,以便后续特征工程阶段灵活选择聚合窗口和变换方式。
4.1 交易金额特征
金额是反洗钱最直接的数值信号。洗钱行为常表现为整数交易、接近阈值交易、结构化拆分交易等。原始金额特征应覆盖以下维度:
| 特征名称 | 定义 | 典型洗钱信号 |
|---|---|---|
txn_amount |
单笔交易金额(原始值) | 接近大额报告阈值(如5万/20万) |
amount_roundness |
金额是否为整数或接近整数(如10000、99999) | 整数交易占比异常高 |
amount_currency |
交易币种(如CNY、USD、EUR) | 频繁使用非本地币种 |
amount_sign |
交易方向(+入金 / -出金) | 短期内入出金金额严重不对称 |
amount_vs_avg |
单笔金额 / 该客户历史平均金额 | 突然偏离个人基线 |
实战案例:某支付机构发现,大量交易金额集中在19,800~19,999元区间,恰好低于20,000元大额报告阈值。通过提取
amount_roundness 和 amount_vs_avg 特征,模型成功识别出该结构化拆分团伙。
4.2 交易频率特征
频率特征反映交易行为的节奏和密度。洗钱账户常表现为“短时高频”或“长时静默后突然活跃”。原始频率特征包括:
- 交易计数:单位时间(日/小时/分钟)内的交易笔数。
- 交易间隔:相邻两笔交易的时间差(秒/分钟)。
- 活跃时段占比:交易发生在工作时段 vs 非工作时段的比例。
- 零交易天数:连续无交易的天数(静默期长度)。
- 交易密度:单位金额对应的交易笔数(笔数/万元)。
# 原始频率特征提取示例(Python伪代码)
import pandas as pd
def extract_frequency_features(txn_df):
# 按客户分组,按时间排序
txn_df = txn_df.sort_values(['customer_id', 'txn_time'])
# 交易间隔(秒)
txn_df['time_diff_sec'] = txn_df.groupby('customer_id')['txn_time'].diff().dt.total_seconds()
# 日交易计数
txn_df['txn_date'] = txn_df['txn_time'].dt.date
txn_df['daily_txn_count'] = txn_df.groupby(['customer_id', 'txn_date'])['txn_id'].transform('count')
# 是否为非工作时段(22:00-06:00)
txn_df['is_off_hour'] = ((txn_df['txn_time'].dt.hour >= 22) |
(txn_df['txn_time'].dt.hour < 6)).astype(int)
return txn_df
注意:频率特征对时间窗口敏感。建议同时保留原始时间戳和多个窗口(1小时/6小时/24小时/7天)的计数,供后续特征选择阶段评估最佳窗口。
4.3 对手方特征
对手方特征刻画交易对手的风险属性。洗钱网络常涉及“新开户对手方”、“高风险地区对手方”、“多对一集中交易”等模式。原始对手方特征包括:
| 特征名称 | 定义 | 数据来源 |
|---|---|---|
counterparty_id |
对手方唯一标识 | 交易流水 |
counterparty_type |
个人/企业/对公账户 | 客户主数据 |
counterparty_tenure |
对手方开户时长(天) | 客户主数据 |
counterparty_risk_level |
对手方风险等级(低/中/高) | 风控系统 |
is_new_counterparty |
该对手方是否首次与本客户交易 | 历史交易 |
counterparty_region |
对手方注册地/开户行所在地 | 客户主数据 |
关键洞察:在原始特征层,对手方特征应保留“一对多”关系。例如,一个客户可能对应多个对手方,每个对手方都有独立的
counterparty_risk_level。后续聚合时再压缩为“最大风险等级”、“高风险对手方占比”等统计量。
4.4 地理位置特征
地理位置特征用于检测“异地交易”、“跨境交易”、“高风险地区交易”等异常行为。原始地理位置特征包括:
- 交易发生地:IP地址、GPS坐标、ATM机编号、网点代码。
- 客户常住地:注册地址、常用登录IP归属地。
- 对手方所在地:对手方开户行所在地、注册地。
- 地理距离:交易发生地与客户常住地之间的直线距离(km)。
- 高风险地区标记:是否涉及FATF高风险司法管辖区、国内反洗钱重点监控地区。
# 地理距离计算示例
from geopy.distance import geodesic
def calc_distance(lat1, lon1, lat2, lon2):
"""计算两点间地理距离(公里)"""
return geodesic((lat1, lon1), (lat2, lon2)).kilometers
# 示例:客户常住地 vs 交易发生地
txn_df['geo_distance_km'] = txn_df.apply(
lambda row: calc_distance(row['home_lat'], row['home_lon'],
row['txn_lat'], row['txn_lon']),
axis=1
)
数据质量提示:IP地址定位精度有限,建议结合多源数据(IP、GPS、网点地址)交叉验证。对于移动端交易,GPS坐标精度较高,但需注意隐私合规要求。
4.5 时间模式特征
时间模式特征捕捉交易的时间规律性。洗钱行为常表现为“非正常时间交易”、“节假日交易激增”、“周期性转账”等。原始时间特征包括:
| 特征名称 | 定义 | 示例值 |
|---|---|---|
txn_hour |
交易发生的小时(0-23) | 3(凌晨3点) |
txn_day_of_week |
交易发生的星期几(0=周一) | 6(周日) |
is_weekend |
是否为周末 | 1 |
is_holiday |
是否为法定节假日 | 0 |
txn_month_day |
交易发生的月内日期(1-31) | 15 |
txn_quarter |
交易发生的季度(1-4) | 4 |
time_since_last_txn |
距离上一笔交易的时间(秒) | 3600 |
常见陷阱:时间特征容易引入“未来信息”。例如,在实时推理场景中,
time_since_last_txn 只能基于历史数据计算,不能使用未来交易。务必在特征工程中明确时间窗口边界。
4.6 原始特征体系总览
以下SVG图展示了五大维度原始特征的完整体系结构,以及各维度之间的交叉关系:
4.7 原始特征提取流程
在实际工程中,原始特征提取通常遵循以下标准化流程:
- 数据接入:从交易流水表、客户主数据表、渠道日志表读取原始数据。
- 字段映射:将业务字段映射为标准化特征名称(如
txn_amount、txn_time)。 - 缺失值处理:对地理位置、对手方信息等缺失字段,使用占位符(如 -1、'UNKNOWN')标记。
- 异常值截断:对金额、距离等连续值,进行 99.9% 分位数截断,防止极端值影响后续聚合。
- 类型转换:将时间戳转为 datetime 类型,将分类字段(如币种、对手方类型)转为 category 类型。
- 特征存储:将原始特征写入特征存储系统(如 Feature Store),供下游特征工程和模型训练使用。
# 原始特征提取完整流程示例
def build_raw_features(txn_raw, customer_raw):
# 1. 数据接入与合并
df = txn_raw.merge(customer_raw, on='customer_id', how='left')
# 2. 字段映射与标准化
df.rename(columns={
'trans_amount': 'txn_amount',
'trans_time': 'txn_time',
'trans_currency': 'txn_currency',
'trans_direction': 'txn_direction'
}, inplace=True)
# 3. 缺失值处理
df['counterparty_risk_level'] = df['counterparty_risk_level'].fillna('UNKNOWN')
df['geo_latitude'] = df['geo_latitude'].fillna(-1.0)
df['geo_longitude'] = df['geo_longitude'].fillna(-1.0)
# 4. 异常值截断
upper_bound = df['txn_amount'].quantile(0.999)
df['txn_amount'] = df['txn_amount'].clip(upper=upper_bound)
# 5. 类型转换
df['txn_time'] = pd.to_datetime(df['txn_time'])
df['txn_currency'] = df['txn_currency'].astype('category')
# 6. 时间特征提取
df['txn_hour'] = df['txn_time'].dt.hour
df['txn_day_of_week'] = df['txn_time'].dt.dayofweek
df['is_weekend'] = df['txn_day_of_week'].isin([5, 6]).astype(int)
return df
工程建议:原始特征层应保持“宽表”结构,每笔交易一行,包含所有原始字段。后续特征工程阶段再根据模型需求进行聚合、变换和筛选。宽表结构便于回溯和调试,避免信息丢失。
4.8 原始特征质量评估
构建完成后,需对原始特征进行质量评估,确保特征可用性:
| 评估维度 | 检查项 | 合格标准 |
|---|---|---|
| 完整性 | 缺失率 | 关键字段缺失率 < 5% |
| 一致性 | 数据类型、取值范围 | 无类型错误,值在预期范围内 |
| 时效性 | 数据延迟 | 实时场景延迟 < 1分钟 |
| 唯一性 | 交易ID重复率 | 重复率 < 0.1% |
| 分布合理性 | 金额、频率分布 | 无明显异常峰值或断崖 |
通过以上五个维度的原始特征设计,我们为后续的衍生特征构建、特征选择和模型训练奠定了坚实的数据基础。下一阶段将基于这些原始特征,进行聚合统计、时序变换和交叉组合,生成更具判别力的高级特征。