4. 数据质量探查:使用 describe() 与 summary() 进行统计摘要、空值检测与异常值初步识别
数据质量是风控模型的基石。在 Spark 中,describe() 和 summary() 是快速了解数值型字段分布、发现缺失与异常的首选工具。本节将演示如何通过这两个方法生成统计摘要,并结合空值检测与业务规则完成初步数据清洗。
4.1 统计摘要:describe() 与 summary() 对比
| 方法 | 输出统计量 | 适用场景 | 注意事项 |
|---|---|---|---|
describe() |
count, mean, stddev, min, max | 快速查看数值字段的集中趋势与离散程度 | 默认只对数值列生效;缺失值不计入 count |
summary() |
count, mean, stddev, min, 25%, 50%, 75%, max | 需要分位数判断分布偏态与异常阈值 | 支持指定分位点;对非数值列返回 null |
风控经验:在信贷场景中,
summary() 的 25%/75% 分位数可直接用于设定“正常区间”,超出 1.5 倍 IQR 的值标记为疑似异常。
# 加载数据
df = spark.read.parquet("hdfs://data/risk/raw_transactions.parquet")
# 使用 describe() 快速查看
df.describe().show()
# 使用 summary() 获取分位数
df.summary().show()
# 指定自定义分位点
df.summary("count", "min", "25%", "50%", "75%", "max").show()
4.2 空值检测:从全局到字段级
空值在风控数据中普遍存在,例如“收入字段”缺失可能暗示用户信息不完整。Spark 提供多种空值检测方式:
- 全局空值统计:使用
select([count(when(isnan(c) | col(c).isNull(), c)).alias(c) for c in df.columns])生成每列空值计数。 - 空值率计算:将空值计数除以总行数,得到缺失比例,用于决定填充或删除策略。
- 空值分布可视化:通过
groupBy聚合空值在关键维度(如时间、渠道)的分布。
from pyspark.sql.functions import col, isnan, when, count
# 逐列统计空值数量
null_counts = df.select([
count(when(isnan(c) | col(c).isNull(), c)).alias(c)
for c in df.columns
])
null_counts.show()
# 计算空值率
total_rows = df.count()
null_rates = null_counts.select([
(col(c) / total_rows).alias(c + "_null_rate")
for c in df.columns
])
null_rates.show()
阈值建议:空值率 < 5% 可直接删除;5%–30% 考虑均值/中位数填充;> 30% 需评估字段业务价值,必要时剔除。
4.3 异常值初步识别:基于统计量与业务规则
异常值识别是风控特征工程的关键前置步骤。结合 summary() 输出的分位数与业务常识,可快速锁定可疑记录:
- 基于 IQR 的离群点检测:计算 Q1 和 Q3,定义 IQR = Q3 - Q1,正常区间为 [Q1 - 1.5*IQR, Q3 + 1.5*IQR]。
- 基于业务阈值的硬性过滤:例如“年龄 < 18 或 > 100”、“交易金额 < 0”等直接判定为异常。
- 基于 Z-Score 的标准化检测:对近似正态分布的字段,|Z| > 3 视为异常。
# 使用 summary() 获取分位数
quantiles = df.approxQuantile("amount", [0.25, 0.75], 0.01)
Q1, Q3 = quantiles[0], quantiles[1]
IQR = Q3 - Q1
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR
# 标记异常值
df_with_flag = df.withColumn(
"is_outlier",
(col("amount") < lower_bound) | (col("amount") > upper_bound)
)
# 查看异常记录数量
df_with_flag.filter(col("is_outlier") == True).count()
风控注意:不要机械删除所有异常值。例如“大额交易”可能是正常的高价值客户行为,需结合业务标签(如是否逾期)做交叉验证。
4.4 数据质量探查流程总览
4.5 实战案例:信用卡交易数据质量探查
以信用卡交易数据集为例,包含字段:txn_id, amount, timestamp, merchant_category, user_age, income。执行以下探查步骤:
# 步骤1:加载数据
txn_df = spark.read.csv("hdfs://data/risk/credit_card_txns.csv", header=True, inferSchema=True)
# 步骤2:统计摘要
txn_df.describe("amount", "user_age", "income").show()
txn_df.summary("count", "min", "25%", "50%", "75%", "max").show()
# 步骤3:空值检测
null_check = txn_df.select([
count(when(isnan(c) | col(c).isNull(), c)).alias(c)
for c in txn_df.columns
])
null_check.show()
# 步骤4:异常值标记(amount 字段)
quantiles = txn_df.approxQuantile("amount", [0.25, 0.75], 0.01)
iqr = quantiles[1] - quantiles[0]
low = quantiles[0] - 1.5 * iqr
high = quantiles[1] + 1.5 * iqr
txn_df = txn_df.withColumn(
"amount_abnormal",
(col("amount") < low) | (col("amount") > high)
)
# 步骤5:输出异常记录
txn_df.filter(col("amount_abnormal") == True).select("txn_id", "amount", "timestamp").show(10)
探查结果示例:amount 字段空值率 2.3%,user_age 空值率 8.1%,income 空值率 15.6%。amount 字段检测到 1,247 条异常值(占 0.5%),其中 89% 为超大额交易,需进一步核实是否为欺诈样本。
4.6 数据质量报告模板
| 字段名 | 数据类型 | 非空计数 | 空值率 | 均值 | 标准差 | 异常值数 | 处理建议 |
|---|---|---|---|---|---|---|---|
| txn_id | string | 500,000 | 0% | — | — | 0 | 主键,无需处理 |
| amount | double | 488,500 | 2.3% | 1,250.80 | 3,420.15 | 1,247 | 空值填充中位数;异常值标记待审核 |
| user_age | int | 459,500 | 8.1% | 34.2 | 12.5 | 320 | 空值填充均值;异常值(<18或>100)删除 |
| income | double | 422,000 | 15.6% | 85,000 | 45,000 | 2,100 | 空值率较高,考虑建模时作为可选特征 |
通过上述探查,我们能够快速定位数据质量问题,为后续的特征工程与模型训练提供可靠的数据基础。在风控场景中,数据质量报告应作为每次实验的必产物,确保模型输入的可信度。