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图展示了五大维度原始特征的完整体系结构,以及各维度之间的交叉关系:

原始特征体系结构图 原始交易特征 交易金额 交易频率 对手方 地理位置 时间模式 原始金额 整数检测 币种标记 交易计数 交易间隔 活跃时段 对手方ID 对手方类型 开户时长 交易IP/坐标 常住地 地理距离 小时/星期 节假日标记 距上笔时间 交叉关系示例 金额 + 频率 → 结构化拆分检测 | 地理位置 + 时间 → 异地深夜交易异常

4.7 原始特征提取流程

在实际工程中,原始特征提取通常遵循以下标准化流程:

  1. 数据接入:从交易流水表、客户主数据表、渠道日志表读取原始数据。
  2. 字段映射:将业务字段映射为标准化特征名称(如 txn_amount、txn_time)。
  3. 缺失值处理:对地理位置、对手方信息等缺失字段,使用占位符(如 -1、'UNKNOWN')标记。
  4. 异常值截断:对金额、距离等连续值,进行 99.9% 分位数截断,防止极端值影响后续聚合。
  5. 类型转换:将时间戳转为 datetime 类型,将分类字段(如币种、对手方类型)转为 category 类型。
  6. 特征存储:将原始特征写入特征存储系统(如 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%
分布合理性 金额、频率分布 无明显异常峰值或断崖

通过以上五个维度的原始特征设计,我们为后续的衍生特征构建、特征选择和模型训练奠定了坚实的数据基础。下一阶段将基于这些原始特征,进行聚合统计、时序变换和交叉组合,生成更具判别力的高级特征。