4. 数据集构建与EDA:模拟交易数据生成、特征分布分析、标签不平衡问题可视化

在构建实时异常交易检测模型之前,高质量的数据集是模型性能的基石。本章将引导你从零开始构建一个模拟交易数据集,并通过探索性数据分析(EDA)深入理解数据特征分布与标签不平衡问题。我们将使用Python的numpy、pandas和matplotlib库完成这一过程。

4.1 模拟交易数据生成

由于真实金融交易数据涉及用户隐私且难以获取,我们采用蒙特卡洛模拟方法生成合成数据。数据生成需遵循以下原则:

  • 时间连续性:交易时间戳按秒递增,模拟真实流水。
  • 特征多样性:包含数值型(金额、频率)、类别型(交易类型、渠道)和时序型特征。
  • 异常注入:人为注入约1%的异常样本,模拟欺诈、盗刷等行为。
数据生成参数表
特征名称 数据类型 正常分布 异常分布 说明
transaction_id 字符串 UUID4 UUID4 唯一标识
timestamp datetime 均匀间隔 均匀间隔 模拟时间戳
amount float LogNormal(μ=4.5, σ=0.8) LogNormal(μ=6.0, σ=1.2) + 随机大额 交易金额(元)
transaction_type 类别 {消费, 转账, 充值} 各33% 转账占比70% 交易类型
channel 类别 {APP, Web, POS} 各33% Web占比60% 交易渠道
hour_of_day int 均匀分布 0-23 凌晨2-5点占比40% 交易小时
is_fraud int 0 1 标签(1为异常)
import numpy as np
import pandas as pd
from datetime import datetime, timedelta

np.random.seed(42)
n_samples = 100000
fraud_ratio = 0.01

# 生成时间戳
base_time = datetime(2024, 1, 1)
timestamps = [base_time + timedelta(seconds=i) for i in range(n_samples)]

# 生成金额
amounts = np.where(
    np.random.rand(n_samples) < fraud_ratio,
    np.random.lognormal(mean=6.0, sigma=1.2, size=n_samples) * np.random.uniform(1, 5, n_samples),
    np.random.lognormal(mean=4.5, sigma=0.8, size=n_samples)
)

# 生成标签
labels = np.random.choice([0, 1], size=n_samples, p=[1-fraud_ratio, fraud_ratio])

# 生成类别特征
types = np.where(labels == 1,
                 np.random.choice(['转账', '消费', '充值'], size=n_samples, p=[0.7, 0.2, 0.1]),
                 np.random.choice(['转账', '消费', '充值'], size=n_samples, p=[0.33, 0.33, 0.34]))

channels = np.where(labels == 1,
                    np.random.choice(['APP', 'Web', 'POS'], size=n_samples, p=[0.2, 0.6, 0.2]),
                    np.random.choice(['APP', 'Web', 'POS'], size=n_samples, p=[0.33, 0.33, 0.34]))

# 生成小时特征
hours = np.where(labels == 1,
                 np.random.choice(range(24), size=n_samples, p=[0.05]*2 + [0.1]*3 + [0.02]*19),
                 np.random.choice(range(24), size=n_samples))

df = pd.DataFrame({
    'transaction_id': [f'TXN{i:08d}' for i in range(n_samples)],
    'timestamp': timestamps,
    'amount': np.round(amounts, 2),
    'transaction_type': types,
    'channel': channels,
    'hour_of_day': hours,
    'is_fraud': labels
})

print(f"数据集形状: {df.shape}")
print(f"异常比例: {df['is_fraud'].mean():.4f}")

4.2 特征分布分析

EDA的核心是理解每个特征在正常样本与异常样本上的分布差异。我们重点关注以下三个维度:

  1. 数值特征分布:交易金额的分布形态,异常样本是否呈现长尾或双峰。
  2. 类别特征分布:交易类型和渠道在两组样本中的占比差异。
  3. 时序特征分布:交易发生的小时分布,异常是否集中在特定时段。
EDA关键发现:在模拟数据中,异常交易的金额均值约为正常交易的3.2倍,且标准差更大;凌晨2-5点的异常交易占比是正常时段的4倍以上。

下面通过SVG图展示交易金额在正常与异常样本上的分布对比:

交易金额分布对比(正常 vs 异常) 金额(正常样本) 金额(异常样本) 频次 正常样本 异常样本 异常样本金额分布更分散,右尾更长,均值显著高于正常样本

4.3 标签不平衡问题可视化

异常交易检测是典型的类别不平衡问题。在模拟数据中,异常样本仅占1%左右。这种极端的标签不平衡会导致模型倾向于预测多数类(正常),从而忽略少数类(异常)。

不平衡问题的三个核心影响:

  • 模型偏差:分类器会偏向多数类,导致召回率极低。
  • 评估误导:整体准确率可能高达99%,但异常样本几乎全被漏检。
  • 训练困难:梯度更新被多数类主导,少数类学习信号微弱。
注意:在后续章节中,我们将采用过采样(SMOTE)、欠采样、代价敏感学习或异常检测算法(如孤立森林)来缓解不平衡问题。EDA阶段必须量化不平衡程度,为后续策略选择提供依据。

下面通过SVG图展示标签分布及不平衡比率:

标签不平衡可视化 正常样本 99,000 占比 99% 异常样本 1,000 (1%) 不平衡比率 ≈ 99:1 极端不平衡:异常样本仅占1%,需采用重采样或代价敏感方法

4.4 特征相关性初步分析

在EDA的最后阶段,我们通过计算特征与标签的相关性,初步筛选对异常检测有区分度的特征。下表展示了模拟数据中主要特征与is_fraud的相关系数:

特征 与标签的相关系数 区分度评估
amount 0.32 中等正相关
hour_of_day -0.18 弱负相关
transaction_type (转账) 0.25 中等正相关
channel (Web) 0.21 弱正相关
timestamp (秒级) 0.01 几乎无关
EDA结论:交易金额、交易类型(转账)和交易渠道(Web)是区分异常与正常交易的关键特征。后续特征工程将围绕这些特征进行交叉组合与变换。

至此,我们完成了模拟交易数据集的构建与EDA分析。下一阶段将基于这些发现进行特征工程与模型训练。