第3章:数据预处理实战:数据清洗、标准化与特征工程入门

各位同学,咱们今天聊点实在的。

数据预处理,说白了就是给原始数据「洗澡」。我见过太多项目,模型选得再好,算法调得再花哨,结果数据一塌糊涂——那真是白忙活。你想想看,垃圾进,垃圾出,这个道理在合规分析里尤其残酷。

3.1 缺失值处理:别让「空」坑了你

缺失值,是合规数据里最常见的坑。我在一个反洗钱项目里遇到过,交易记录里「交易对手」字段空了30%。当时团队差点直接删掉这些行,我拦住了——你猜怎么着?这些缺失恰恰是某些地下钱庄的典型特征。

处理缺失值,我一般分三步走:

  1. 诊断缺失模式:是随机缺失,还是系统性缺失?
  2. 评估缺失比例:低于5%可以删,高于30%要小心
  3. 选择填补策略:均值、中位数、还是模型预测?

核心原则:合规场景下,宁可保留缺失标记,也不要随意填补。因为缺失本身可能就是信号。

代码示例,我习惯用Pandas快速处理:

import pandas as pd
import numpy as np

# 加载数据
df = pd.read_csv('compliance_data.csv')

# 查看缺失情况
print(df.isnull().sum())

# 策略1:删除缺失比例过高的列
df.dropna(thresh=len(df)*0.7, axis=1, inplace=True)

# 策略2:用中位数填补数值型字段
df['amount'].fillna(df['amount'].median(), inplace=True)

# 策略3:分类字段用「未知」标记
df['counterparty'].fillna('UNKNOWN', inplace=True)

我的小技巧:对于时间序列数据,我会用前向填充(ffill)或后向填充(bfill)。比如交易时间戳缺失,用上一笔交易的时间补上,往往比均值更合理。

3.2 异常值检测:揪出「害群之马」

异常值,在合规分析里往往是最有价值的部分。为什么?因为真正的风险行为,往往就藏在那些「不正常」的数据点里。

我记得有一次做供应商合规审查,发现某家公司的交易金额突然暴增100倍。系统自动标记为异常,结果一查,果然是关联交易——这就是异常值的价值。

常用的检测方法,我整理了一张表:

方法 适用场景 优点 缺点
Z-Score 正态分布数据 简单快速 对非正态分布不友好
IQR(四分位距) 偏态分布数据 稳健,不受极端值影响 阈值选择主观
孤立森林 高维数据 处理大规模数据快 解释性差
DBSCAN 空间聚类异常 能发现簇状异常 参数敏感

实战中,我推荐先用IQR做快速筛查:

# 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['is_anomaly'] = (df['amount'] < lower_bound) | (df['amount'] > upper_bound)

print(f"发现 {df['is_anomaly'].sum()} 个异常值")

避坑指南:我曾经在某个项目中,直接用Z-Score把「高净值客户」的正常大额交易误判为异常。后来我学乖了——一定要按业务场景分层检测。不同客户群体,阈值应该不同。

3.3 数据标准化:让不同量纲的数据「对话」

标准化,说白了就是把不同尺度的数据拉到同一个量级。比如交易金额(几百万)和交易次数(几十次),如果不标准化,模型会天然偏向金额大的特征。

我常用的两种方法:

  • Min-Max标准化:缩放到[0,1]区间,适合有边界的数据
  • Z-Score标准化:均值为0,标准差为1,适合有异常值的数据
from sklearn.preprocessing import MinMaxScaler, StandardScaler

# Min-Max标准化
scaler_minmax = MinMaxScaler()
df['amount_scaled'] = scaler_minmax.fit_transform(df[['amount']])

# Z-Score标准化
scaler_std = StandardScaler()
df['amount_standard'] = scaler_std.fit_transform(df[['amount']])

我的习惯:合规数据里如果有明显的异常值,我倾向于用Z-Score。因为Min-Max会被极端值「压扁」正常数据的差异。你想想看,一个100亿的异常交易,会把所有正常交易都挤到0附近。

3.4 数据脱敏:合规分析的「底线」

数据脱敏,这是合规分析的红线。我在做银行项目时,客户明确要求:任何个人身份信息(PII)都不能出现在分析环境中。

常用的脱敏技术:

  1. 替换:用随机生成的假名替换真实姓名
  2. 掩码:只显示部分字符,如身份证号前6位+后4位
  3. 泛化:把具体年龄变成年龄段(20-30岁)
  4. 扰动:在数值上添加随机噪声
# 简单的脱敏示例
import hashlib

# 对姓名进行哈希脱敏
df['name_hash'] = df['name'].apply(lambda x: hashlib.sha256(x.encode()).hexdigest()[:16])

# 对身份证号进行掩码
df['id_masked'] = df['id_number'].apply(lambda x: x[:6] + '****' + x[-4:])

# 对年龄进行泛化
df['age_group'] = pd.cut(df['age'], bins=[0, 18, 30, 45, 60, 100], 
                         labels=['0-18', '19-30', '31-45', '46-60', '60+'])

注意:哈希脱敏并不是绝对安全的。我曾经见过有人用彩虹表反查哈希值。所以对于高敏感字段,建议用加盐哈希或加密算法。

3.5 特征工程入门:从数据中「挖金子」

特征工程,说白了就是把原始数据变成模型能理解的语言。我常说,好的特征工程,比选什么模型都重要。

入门阶段,我建议从这三个方向入手:

  • 数值特征:做对数变换、分箱、交叉特征
  • 类别特征:独热编码、标签编码、目标编码
  • 时间特征:提取年、月、日、星期、是否节假日
# 特征工程示例
# 1. 数值特征:对数变换(处理长尾分布)
df['amount_log'] = np.log1p(df['amount'])

# 2. 类别特征:独热编码
df_encoded = pd.get_dummies(df, columns=['transaction_type'], prefix='type')

# 3. 时间特征:提取星期几
df['transaction_date'] = pd.to_datetime(df['transaction_date'])
df['day_of_week'] = df['transaction_date'].dt.dayofweek
df['is_weekend'] = df['day_of_week'].isin([5, 6]).astype(int)

我的经验:在合规场景里,「比率特征」往往比「绝对值特征」更有用。比如「月交易金额/月收入」这个比率,比单纯的交易金额更能反映异常行为。我做过一个项目,就是靠这个比率发现了洗钱账户。

3.6 本章知识体系总览

下面这张图,是我梳理的本章核心逻辑。你可以把它当作一个检查清单,做数据预处理时对照着来:

数据预处理实战知识体系 原始数据 数据清洗 缺失值处理 异常值检测 重复值去重 数据变换 标准化/归一化 数据脱敏 特征工程 干净、可用的数据

嗯,这张图把整个流程串起来了。从原始数据开始,先做清洗(缺失值、异常值、重复值),再做变换(标准化、脱敏、特征工程),最后得到干净可用的数据。每一步都有坑,但每一步也都有价值。

好了,这一章的内容就到这里。数据预处理是合规分析的地基,地基打不牢,后面建多高的楼都白搭。希望你能把这些方法用到自己的项目里,真正感受到「数据清洗」带来的成就感。


公众号:蓝海资料掘金营,微信deep3321