3. 数据采集与预处理:数据源介绍(CSV、数据库)、缺失值处理、重复值处理、数据类型转换

在构建异常交易检测模型之前,数据采集与预处理是决定模型质量的基础环节。原始数据通常来自异构数据源,包含大量噪声、缺失和冗余信息。本章将系统讲解如何从 CSV 文件和关系型数据库中采集交易样本,并完成缺失值、重复值处理及数据类型转换,确保输入模型的数据干净、一致、可用。

3.1 数据源介绍

异常交易样本的常见来源包括离线文件(CSV)和在线数据库。两种数据源在格式、访问方式和适用场景上存在显著差异。

特性 CSV 文件 关系型数据库(如 MySQL / PostgreSQL)
存储格式 纯文本,逗号分隔,无结构约束 结构化表,字段类型、约束、索引完整
访问方式 文件 I/O 读取,适合单机或小批量 SQL 查询,支持并发、事务、权限控制
数据量级 通常 ≤ 1GB,适合原型验证 可扩展至 TB 级,适合生产环境
元数据 无或仅首行表头 完整的数据字典、字段注释、关系约束
典型场景 历史交易快照、离线分析、模型训练样本 实时交易流水、在线特征计算、增量更新
实践建议:在课程项目中,我们使用 CSV 作为初始样本导入工具,便于快速迭代;生产级风控系统则必须从数据库直接拉取,以保证数据一致性和时效性。

3.2 缺失值处理

缺失值是异常交易数据中的常见问题,可能由系统故障、字段可选、数据合并遗漏等原因造成。处理缺失值前,必须先识别缺失模式。

3.2.1 缺失模式识别

  • 完全随机缺失(MCAR):缺失与观测数据无关,如网络中断导致部分记录未写入。
  • 随机缺失(MAR):缺失依赖于其他观测变量,如高金额交易更可能缺失风控评分字段。
  • 非随机缺失(MNAR):缺失与缺失值本身有关,如欺诈交易故意隐藏用户 IP。

3.2.2 常用处理方法

方法 适用场景 注意事项
删除缺失行 缺失比例 < 5%,且为 MCAR 可能丢失有效样本,导致样本偏差
均值/中位数填充 数值型特征,缺失比例 ≤ 20% 降低方差,可能削弱异常检测能力
众数填充 分类型特征 可能引入模式偏差
前向/后向填充 时间序列交易数据 仅适用于有序数据
模型预测填充 缺失比例较高,特征间关联强 计算成本高,需避免数据泄露
# 示例:使用 pandas 进行缺失值处理
import pandas as pd
import numpy as np

# 读取交易样本
df = pd.read_csv('transaction_sample.csv')

# 查看缺失比例
missing_ratio = df.isnull().mean()
print("缺失比例:\n", missing_ratio[missing_ratio > 0])

# 删除缺失比例超过 50% 的列
df.drop(columns=df.columns[df.isnull().mean() > 0.5], inplace=True)

# 数值列用中位数填充
num_cols = df.select_dtypes(include=[np.number]).columns
df[num_cols] = df[num_cols].fillna(df[num_cols].median())

# 分类型用众数填充
cat_cols = df.select_dtypes(include=['object']).columns
for col in cat_cols:
    df[col].fillna(df[col].mode()[0], inplace=True)
注意:在风控场景中,缺失值本身可能携带信息。例如,缺失“交易 IP”字段的记录,欺诈概率往往更高。建议在填充前先创建“是否缺失”的指示特征,保留缺失信号。

3.3 重复值处理

重复值会导致模型对相同样本过度学习,降低泛化能力,并扭曲统计分布。异常交易数据中的重复可能来自系统重试、数据合并、恶意刷单等。

3.3.1 重复类型

  • 完全重复:所有字段完全相同,通常为系统冗余。
  • 部分重复:关键字段(交易 ID、时间、金额)相同,但非关键字段有差异。
  • 业务重复:同一笔交易被多次记录,如支付网关与银行流水重复。

3.3.2 处理策略

策略 操作 风控场景建议
完全去重 保留第一条,删除其余 适用于系统冗余导致的重复
基于关键字段去重 按交易 ID、时间、金额分组,保留最新或最完整记录 适用于业务重复
聚合去重 对重复组进行统计聚合(计数、均值) 适用于需要保留重复频次信息的场景
# 示例:重复值检测与处理
# 检测完全重复行
duplicates = df.duplicated()
print(f"完全重复行数: {duplicates.sum()}")

# 删除完全重复
df.drop_duplicates(inplace=True)

# 基于关键字段去重:保留交易时间最新的记录
df.sort_values('transaction_time', ascending=False, inplace=True)
df.drop_duplicates(subset=['transaction_id', 'amount'], keep='first', inplace=True)

3.4 数据类型转换

数据类型不匹配是数据预处理中的常见陷阱。CSV 文件读取后,所有字段默认可能被识别为字符串;数据库导入后,时间戳、金额、分类编码等字段也需要显式转换。

3.4.1 常见转换场景

原始类型 目标类型 转换原因 示例
字符串 datetime 时间序列分析、窗口聚合 '2025-01-15 14:30:00' → datetime
字符串 float / int 数值计算、统计建模 '1,234.56' → 1234.56
字符串 category 分类特征编码、减少内存 'high', 'medium', 'low' → category
int bool 二值标志位 0 / 1 → False / True
# 示例:数据类型转换
# 时间戳转换
df['transaction_time'] = pd.to_datetime(df['transaction_time'])

# 金额字段:去除千分位逗号并转为浮点数
df['amount'] = df['amount'].str.replace(',', '').astype(float)

# 分类编码
df['risk_level'] = df['risk_level'].astype('category')

# 二值标志位
df['is_fraud'] = df['is_fraud'].astype(bool)

# 验证转换后的数据类型
print(df.dtypes)

3.5 数据预处理流程总览

以下 SVG 图展示了从原始数据源到干净训练样本的完整预处理流水线,包含本章涉及的三个核心步骤及其顺序关系。

数据预处理流程总览 CSV 文件 关系型数据库 API / 流式数据 数据合并与统一 缺失值处理 重复值处理 数据类型转换
流程要点:预处理顺序不可随意调换。先处理缺失值,再处理重复值,最后进行类型转换,可以避免因类型错误导致的去重失败或填充异常。建议在每一步后执行数据质量检查,确保转换结果符合预期。

3.6 数据质量检查清单

完成预处理后,建议使用以下清单验证数据质量,确保样本可用于模型训练。

  • 完整性:所有关键字段无缺失值,缺失比例控制在 5% 以内。
  • 唯一性:交易 ID 或业务主键无重复,重复率低于 0.1%。
  • 一致性:金额、时间等数值字段类型正确,无异常格式。
  • 时效性:时间戳字段在合理范围内,无未来时间或过旧数据。
  • 平衡性:正负样本比例初步统计,为后续采样策略提供依据。
# 数据质量检查示例
def check_data_quality(df):
    report = {}
    report['total_rows'] = len(df)
    report['missing_ratio'] = df.isnull().mean().max()
    report['duplicate_ratio'] = df.duplicated().mean()
    report['dtypes'] = df.dtypes.to_dict()
    return report

quality_report = check_data_quality(df)
print(quality_report)