第一章:数据探索与可视化基础
做风控模型,尤其是无监督异常检测,有个铁律:数据质量决定模型上限。我见过太多人一上来就调参、堆模型,结果跑出来的结果根本没法解释。说白了,你连数据长什么样都不知道,怎么指望模型帮你找出异常?
这一章,我们就从最基础的数据探索开始。我会带你走一遍我平时做项目的标准流程:加载数据、看统计量、查缺失值、画分布图。嗯,这些听起来简单,但坑不少。
1.1 加载数据集
我个人习惯用 Pandas 来加载数据。不管数据是 CSV、Excel 还是数据库,Pandas 基本都能搞定。这里我们用一个模拟的信用卡交易数据集做演示。
import pandas as pd
import numpy as np
# 加载数据
df = pd.read_csv('transaction_data.csv')
print(f'数据集形状: {df.shape}')
print(f'列名: {df.columns.tolist()}')
加载完后,第一件事就是看数据长什么样。我一般会用 df.head() 和 df.info() 快速扫一眼。
# 查看前5行
print(df.head())
# 查看数据类型和内存占用
print(df.info())
这里有个坑:df.info() 会告诉你每列的数据类型。如果某个数值列显示为 object,那八成是混入了字符串。我在项目中遇到过,某次加载交易金额列,因为有个别记录写了 "N/A",整列变成了字符串。你想想看,后面做统计全乱套了。
1.2 描述性统计
描述性统计是快速了解数据分布的法宝。Pandas 的 describe() 方法能一口气给出均值、标准差、四分位数等关键指标。
# 数值列的统计摘要
print(df.describe())
# 类别列的统计摘要
print(df.describe(include='object'))
我个人习惯重点关注几个指标:
- 均值 vs 中位数:如果两者差距大,说明数据有偏态分布,可能有异常值。
- 标准差:太大说明数据波动剧烈,异常检测的难度会上升。
- 最大值和最小值:一眼就能看出有没有离谱的值。比如交易金额出现负数,那肯定有问题。
实战经验:我在做电商反欺诈时,发现交易金额的均值是 200 元,但中位数只有 50 元。一查,原来是几个大额交易把均值拉高了。这些大额交易本身不一定是异常,但如果你用均值做阈值,小额的正常交易反而会被误判。所以,别只看均值。
1.3 缺失值分析
缺失值是无监督学习的大敌。很多算法(比如孤立森林、LOF)不能处理空值,所以必须提前处理。
我一般用两步走:
- 统计缺失比例:看看每列缺失了多少。
- 分析缺失模式:缺失是随机的,还是集中在某些特征上?
# 统计每列缺失值数量和比例
missing = df.isnull().sum()
missing_pct = (missing / len(df)) * 100
missing_df = pd.DataFrame({'缺失数量': missing, '缺失比例(%)': missing_pct})
print(missing_df[missing_df['缺失数量'] > 0])
注意:缺失比例超过 50% 的列,我建议直接删除。我曾经在一个项目中,有一列缺失了 70%,我硬着头皮去填充,结果模型效果反而更差。有时候,放弃也是一种策略。
如果缺失比例不高(比如 5% 以内),我通常会用中位数或众数填充。但要注意,填充本身会引入偏差。对于异常检测来说,缺失本身可能就是一个信号。比如,某个用户的地址信息缺失,可能意味着他是新注册的账号,交易风险更高。
1.4 单变量分布可视化
光看数字不够,还得画图。一张好的分布图,比一堆统计数字更直观。我常用的工具有 Matplotlib 和 Seaborn。
1.4.1 直方图 + 核密度估计
直方图能展示数据的分布形状。加上核密度估计(KDE)曲线,能更平滑地看出分布趋势。
import matplotlib.pyplot as plt
import seaborn as sns
plt.figure(figsize=(10, 6))
sns.histplot(df['amount'], bins=50, kde=True)
plt.title('交易金额分布')
plt.xlabel('金额')
plt.ylabel('频次')
plt.show()
画完图,我会问自己几个问题:
- 分布是正态的吗?还是长尾的?
- 有没有明显的双峰?双峰可能意味着有两种不同的交易模式。
- 有没有离群点?比如金额特别大的那些点。
1.4.2 箱线图
箱线图是检测异常值的利器。它用四分位数来定义正常范围,超出 1.5 倍 IQR 的点会被标记为异常。
plt.figure(figsize=(8, 4))
sns.boxplot(x=df['amount'])
plt.title('交易金额箱线图')
plt.show()
小技巧:箱线图标记的异常点,不一定都是真正的异常。比如,大额交易可能是正常的批发订单。所以,箱线图只能给你线索,不能给你结论。我一般会结合业务知识,再决定这些点要不要处理。
1.4.3 类别特征的分布
对于类别特征(比如交易类型、商户类别),我会用柱状图看频次分布。
plt.figure(figsize=(12, 5))
df['transaction_type'].value_counts().plot(kind='bar')
plt.title('交易类型分布')
plt.xlabel('交易类型')
plt.ylabel('交易笔数')
plt.xticks(rotation=45)
plt.show()
这里要注意:如果某个类别的样本极少(比如占比不到 1%),那它本身可能就是异常。我在做支付风控时,发现 "跨境汇款" 这个类型只占 0.3%,但其中欺诈比例高达 15%。所以,低频类别要格外关注。
知识体系总览
下面这张图,是我自己总结的数据探索流程。你可以把它当作一个检查清单,每次做项目时对照着来。
这张图把整个流程串起来了。你从加载数据开始,一步步往下走,每一步都会给你新的信息。我个人习惯是,每做完一步,就在心里问一句:「这个结果合理吗?」如果发现不合理的地方,比如某个特征的分布完全不符合业务常识,那就得回头检查数据了。
核心要点:数据探索不是一次性工作。你可能会在建模过程中发现新的问题,然后回来重新探索。所以,保持好奇,保持怀疑。这是做风控的基本素养。