4. 数据剖析与探索:数据概况统计、缺失值分析、异常值检测、分布分析

数据剖析,说白了就是给数据做个体检。拿到一张表,别急着上模型,先摸摸它的底细。我见过太多人,数据还没看明白就往上堆算法,结果跑出来的结果自己都不敢信。

这一节,我们聊聊怎么系统地做数据探索。四个维度:概况统计、缺失值、异常值、分布分析。按这个顺序走一遍,你对数据的脾气就摸得差不多了。

4.1 数据概况统计

先看整体,再看局部。我习惯用 df.describe() 开道,几秒钟就能拿到数值列的统计摘要。

import pandas as pd
import numpy as np

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

# 数值列概况
print(df.describe())

# 分类列概况
print(df.describe(include=['object']))

输出里重点看什么?

  • count:非空记录数。如果某列 count 明显少于总行数,说明有缺失。
  • min / max:极值。有没有明显不合理的数据?比如订单金额出现负数。
  • mean / std:均值和标准差。标准差太大,说明数据波动剧烈,要小心。
  • 25% / 50% / 75%:四分位数。能帮你判断数据是否偏态。
我的习惯:先看 count 列,再扫 min 和 max。如果某列 count 比总行数少 5% 以上,我会标记为「需要处理」。如果 min 出现负数但业务上不该有负数,直接标异常。

4.2 缺失值分析

缺失值不是小事。它可能意味着系统 bug、人为漏填、或者数据源本身就不完整。

先统计缺失比例:

# 缺失值统计
missing = df.isnull().sum()
missing_pct = (df.isnull().sum() / len(df)) * 100

missing_df = pd.DataFrame({
    '缺失数量': missing,
    '缺失比例(%)': missing_pct
})
print(missing_df[missing_df['缺失数量'] > 0].sort_values('缺失比例(%)', ascending=False))

拿到结果后,怎么判断?我一般按这个标准来:

缺失比例 处理建议
< 1% 直接删除或填充均值/中位数
1% - 5% 用中位数、众数或模型预测填充
5% - 20% 需要分析缺失原因,考虑是否与目标变量相关
> 20% 慎重。如果列不重要,直接删除;如果重要,必须溯源
我曾经踩过的坑:有一次做客户流失分析,发现「最近一次登录时间」缺失了 30%。我以为是系统没记录,直接填充了平均值。结果模型效果极差。后来一查,缺失的其实是已经流失的客户——系统在客户注销后清空了登录记录。缺失本身就是一个信号,不能随便填。

4.3 异常值检测

异常值,就是那些「看着不对劲」的数据。比如订单金额 100 万,但正常范围是 100-5000。这种数据要么是录入错误,要么是特殊场景。

我常用的方法有三种:

4.3.1 箱线图法(IQR)

def detect_outliers_iqr(data, column):
    Q1 = data[column].quantile(0.25)
    Q3 = data[column].quantile(0.75)
    IQR = Q3 - Q1
    lower_bound = Q1 - 1.5 * IQR
    upper_bound = Q3 + 1.5 * IQR
    outliers = data[(data[column] < lower_bound) | (data[column] > upper_bound)]
    return outliers

outliers = detect_outliers_iqr(df, 'amount')
print(f'异常值数量: {len(outliers)}')

4.3.2 Z-Score 法

from scipy import stats

z_scores = np.abs(stats.zscore(df['amount']))
outliers_z = df[z_scores > 3]
print(f'Z-Score 异常值数量: {len(outliers_z)}')

4.3.3 业务规则法

这个方法最靠谱。比如订单金额不能为负,年龄不能超过 120。直接写规则过滤:

# 业务规则
invalid_amount = df[df['amount'] <= 0]
invalid_age = df[df['age'] > 120]

print(f'金额异常: {len(invalid_amount)} 条')
print(f'年龄异常: {len(invalid_age)} 条')
核心原则:异常值不一定要删除。先问自己三个问题:
1. 这个值在业务上可能吗?
2. 它是录入错误还是真实事件?
3. 删除后会不会丢失重要信息?
如果答案是「可能真实」,先保留,标记出来,后续分析时单独处理。

4.4 分布分析

分布分析,就是看数据长什么样。是正态分布?偏态?还是双峰?

我一般用直方图和 Q-Q 图来快速判断。

import matplotlib.pyplot as plt
import seaborn as sns

# 直方图 + 密度曲线
plt.figure(figsize=(10, 5))
sns.histplot(df['amount'], kde=True, bins=50)
plt.title('订单金额分布')
plt.show()

# Q-Q 图
from scipy import stats
stats.probplot(df['amount'], dist="norm", plot=plt)
plt.title('Q-Q 图')
plt.show()

分布分析能告诉你什么?

  • 正态分布:很多统计方法的前提,如果数据偏态严重,可能需要做变换。
  • 长尾分布:少数极端值拉高了均值,中位数更能代表「典型值」。
  • 双峰分布:数据可能来自两个不同的群体,需要拆分分析。
  • 离散分布:值集中在几个点上,比如评分数据 1-5 分。
一个小技巧:如果直方图看不清楚,试试分位数-分位数图(Q-Q 图)。点越接近对角线,数据越接近正态分布。偏离太远,就要考虑做对数变换或 Box-Cox 变换。

4.5 知识体系总览

下面这张图,把数据剖析的四个维度串起来了。你可以把它当作检查清单,每次做数据探索时对照着走一遍。

数据剖析与探索 · 知识体系 数据剖析 概况统计 缺失值分析 异常值检测 分布分析 count / mean / std min / max / 分位数 缺失比例统计 缺失模式分析 IQR 箱线图法 Z-Score 法 业务规则法 直方图 + KDE Q-Q 图 核心原则:先概况 → 再缺失 → 再异常 → 最后分布 每一步都要结合业务理解,不要机械执行

4.6 实战建议

数据剖析不是一次性工作。我建议你把它做成一个可复用的脚本,每次拿到新数据就跑一遍。这样能快速发现数据质量问题,避免后期返工。

嗯,这里要注意:不要只看数字,要结合业务。比如缺失率 10%,如果是因为新功能上线还没积累数据,那就不是问题。但如果是因为接口报错导致数据没落库,那就是大问题。

数据剖析做得好,根因分析就成功了一半。剩下的,就是顺着线索往下挖了。