深入浅出:利用 Python 掌握统计学中的 68-95-99.7 法则

在数据科学、统计分析甚至机器学习的日常工作中,我们经常需要处理大量的数据。面对纷繁复杂的数据,我们如何快速判断数据是否存在异常?或者如何理解数据的分布规律呢?这就需要用到统计学中最重要的“黄金法则”之一——68-95-99.7 法则,也就是我们熟知的经验法则(Empirical Rule)或三西格玛法则(Three-Sigma Rule)。

在这篇文章中,我们将一起深入探讨这个法则背后的数学原理,并利用强大的 Python 库(如 SciPy 和 Matplotlib)来直观地验证它。我们不仅会了解它是什么,还会学习如何通过代码在实际项目中应用它,甚至探讨它在异常检测中的具体用途。准备好和我一起探索正态分布的奥秘了吗?

什么是 68-95-99.7 法则?

简单来说,经验法则描述了正态分布(Normal Distribution)数据中数值与均值和标准差之间的关系。对于任何服从正态分布的数据集,只要我们知道它的均值($\mu$)和标准差($\sigma$),就可以做出非常精确的预测:

  • 68% 的数据会落在均值周围的 1 个标准差 范围内(即 $\mu \pm 1\sigma$)。
  • 95% 的数据会落在均值周围的 2 个标准差 范围内(即 $\mu \pm 2\sigma$)。
  • 99.7% 的数据会落在均值周围的 3 个标准差 范围内(即 $\mu \pm 3\sigma$)。

这意味着,如果你手里的数据符合正态分布,那么几乎所有的数据(99.7%)都会距离平均值不超过 3 个标准差。如果有一个数据点落在了这个范围之外,我们通常有极大的把握认为它是一个异常值(Outlier)。

为什么这很重要?

想象一下,你正在分析一家工厂生产的零件尺寸。你知道平均尺寸是 10cm,标准差是 0.1cm。根据经验法则,你可以立即断定:

  • 约 68% 的零件尺寸在 9.9cm 到 10.1cm 之间。
  • 几乎所有(99.7%)的零件尺寸都在 9.7cm 到 10.3cm 之间。

如果你突然测量出一个尺寸为 10.5cm 的零件,你应该立刻警觉起来,因为生产过程可能出现了问题。这就是统计学赋予我们的洞察力。

理论基础:累积分布函数 (CDF)

要编写代码验证这个法则,我们需要理解一个核心概念:累积分布函数(Cumulative Distribution Function,简称 CDF)。

CDF 能够告诉我们,在一个分布中,随机变量小于或等于某个特定值的概率是多少。为了计算“落在两个数值之间”的概率(比如 $1\sigma$ 到 $-1\sigma$ 之间),我们需要计算两个 CDF 值的差:

$$ P(a < X \le b) = CDF(b) – CDF(a) $$

在 Python 中,我们可以利用 INLINECODEaad81895 库中的 INLINECODEef91acb1 函数来轻松完成这个计算。

使用 Python 验证经验法则

让我们开始动手写代码吧。首先,我们需要导入必要的库。为了验证我们的理论,我们假设使用标准的正态分布,即均值 $\mu = 0$,标准差 $\sigma = 1$。

示例 1:基础数学验证

这是最核心的计算逻辑。我们将使用 SciPy 来计算确切的概率值,看看它们是否真的接近 0.68, 0.95 和 0.997。

# 导入必要的库
from scipy.stats import norm

# 定义均值和标准差
# 在标准正态分布中,均值为 0,标准差为 1
mean = 0  
std_dev = 1  # SD 代表 Standard Deviation

# 计算 1 个标准差范围内的概率 ( -1 到 1 )
# 逻辑:P(X < 1) - P(X < -1)
prob_1_sd = norm.cdf(1 * std_dev, loc=mean, scale=std_dev) - norm.cdf(-1 * std_dev, loc=mean, scale=std_dev)

# 计算 2 个标准差范围内的概率 ( -2 到 2 )
prob_2_sd = norm.cdf(2 * std_dev, loc=mean, scale=std_dev) - norm.cdf(-2 * std_dev, loc=mean, scale=std_dev)

# 计算 3 个标准差范围内的概率 ( -3 到 3 )
prob_3_sd = norm.cdf(3 * std_dev, loc=mean, scale=std_dev) - norm.cdf(-3 * std_dev, loc=mean, scale=std_dev)

# 打印结果,使用 f-string 格式化输出,保留 4 位小数
print(f"落在均值周围 1 个标准差内的比例: {prob_1_sd:.4f}")
print(f"落在均值周围 2 个标准差内的比例: {prob_2_sd:.4f}")
print(f"落在均值周围 3 个标准差内的比例: {prob_3_sd:.4f}")

运行结果:

落在均值周围 1 个标准差内的比例: 0.6827
落在均值周围 2 个标准差内的比例: 0.9545
落在均值周围 3 个标准差内的比例: 0.9973

看,正如我们所料!计算结果完美验证了 68.27%, 95.45% 和 99.73% 这一理论数值。norm.cdf 函数帮我们计算了曲线下左侧的累积面积,通过做减法,我们得到了中间区域的面积。

示例 2:可视化正态分布(直观理解)

“一图胜千言”。让我们用 Matplotlib 画出正态分布曲线,并填充出 68%, 95% 和 99.7% 的区域。这将帮助你直观地看到数据的集中程度。

import matplotlib.pyplot as plt
import numpy as np
from scipy.stats import norm

# 1. 准备数据
# 定义 X 轴范围:从 -4 到 4,覆盖了大部分有效区域
x = np.linspace(-4, 4, 1000)
# 计算对应的概率密度函数 PDF 值
y = norm.pdf(x, loc=0, scale=1)

# 2. 设置绘图风格
plt.figure(figsize=(12, 6))
plt.plot(x, y, label=‘标准正态分布‘, color=‘black‘, linewidth=2)

# 3. 填充不同区域,为了直观,我们使用不同的透明度和颜色

# 填充 1 Sigma 区域 (-1 到 1)
plt.fill_between(x, y, where=( (x >= -1) & (x = -3) & (x = -2) & (x = -1) & (x <= 1) ), color='blue', alpha=0.4, label='68% (1 Sigma)')

# 绘制主曲线
plt.plot(x, y, color='black', linewidth=2)

# 添加标题和标签
plt.title("68-95-99.7 法则可视化", fontsize=15)
plt.xlabel("标准差")
plt.ylabel("概率密度")
plt.legend(loc='upper right')
plt.grid(True, alpha=0.3)
plt.show()

通过这段代码,你将看到一个经典的钟形曲线图。你可以清晰地看到:

  • 蓝色区域(最中间)包含了大部分数据。
  • 加上绿色区域,我们几乎覆盖了整个图表的主体。
  • 加上红色区域(最外层),曲线的两端尾巴几乎消失殆尽。这正是“小概率事件”发生的地方。

实战应用:从现实数据中检测异常值

仅仅知道理论是不够的。在实际工作中,我们经常拿到的不是完美的标准正态分布数据,而是具有特定均值和方差的现实数据。让我们模拟一个场景,并编写一个函数来自动检测异常值。

示例 3:非标准正态分布的分析

假设某只股票的日收益率符合正态分布,均值为 0.05%(即 0.0005),标准差为 1.5%(即 0.015)。我们要找出那些“极不可能发生”的异常交易日(超过 3 个标准差)。

import numpy as np
from scipy.stats import norm

def detect_outliers(data):
    """
    根据 3-Sigma 法则检测数据中的异常值
    """
    # 计算均值和标准差
    data_mean = np.mean(data)
    data_std = np.std(data)
    
    # 设定阈值 (上界和下界)
    upper_bound = data_mean + 3 * data_std
    lower_bound = data_mean - 3 * data_std
    
    print(f"数据均值: {data_mean:.5f}")
    print(f"数据标准差: {data_std:.5f}")
    print(f"正常范围: [{lower_bound:.5f}, {upper_bound:.5f}]")
    
    # 筛选出异常值
    outliers = [x for x in data if x > upper_bound or x < lower_bound]
    
    return outliers

# 1. 模拟生成股票收益率数据 (1000天)
# loc=0.0005 (0.05%), scale=0.015 (1.5%)
population = np.random.normal(loc=0.0005, scale=0.015, size=1000)

# 2. 人为添加几个极端的异常数据
# 比如暴跌 5% 或暴涨 6%
population_with_anomalies = np.append(population, [0.06, -0.05, 0.07])

# 3. 运行检测
anomalies = detect_outliers(population_with_anomalies)

print(f"
检测到的异常值数量: {len(anomalies)}")
print(f"异常值列表: {anomalies}")

代码解析:

这段代码首先模拟了一组现实世界的数据(带有非零均值)。然后,我们定义了一个 detect_outliers 函数。它计算数据的均值和标准差,并定义了“正常”的边界($\mu \pm 3\sigma$)。任何落在边界之外的数据都会被标记为异常值。这就是简单的异常检测算法的基础。

进阶技巧与性能优化

作为开发者,我们在处理大规模数据时还需要注意一些细节。以下是几个实用的建议。

1. 性能考虑:避免循环

在示例 3 中,为了演示方便,我们使用了 Python 的列表推导式来筛选异常值。但是,如果你处理的是数百万条数据,这种循环方式效率很低。

最佳实践: 使用 NumPy 的布尔索引(Boolean Indexing)。它利用底层的 C 语言实现,速度极快。

# 优化后的异常检测代码片段
def detect_outliers_optimized(data):
    data_mean = np.mean(data)
    data_std = np.std(data)
    
    # 直接使用布尔运算,不需要 Python 循环
    # 这在大数据集上速度提升非常明显
    is_outlier = (data > (data_mean + 3 * data_std)) | (data < (data_mean - 3 * data_std))
    
    return data[is_outlier]

2. 数据正态性检验

经验法则有一个重要的前提:数据必须服从正态分布。如果你的数据严重偏斜(比如人类的收入分布),那么盲目套用 68-95-99.7 法则会得出错误的结论。

在应用这个法则之前,你可以通过绘制直方图或使用 Q-Q 图来检查数据形状。如果钟形曲线明显不对称,你可能需要先对数据进行转换(例如取对数 Log Transform),或者使用四分位距(IQR)方法来检测异常值。

常见错误与解决方案

错误 1:混淆样本与总体

我们在代码中使用 INLINECODE7e8dbc25 和 INLINECODE8f1784e5。如果你只有一小部分样本数据,计算标准差时通常需要设置 INLINECODEf00f10f3(贝塞尔校正)来得到无偏估计。但在非常大的数据集(如大数据应用)中,INLINECODE5a425036(默认值)也是可以接受的。

错误 2:忘记标准化

如果你想对不同量级的数据(例如身高和体重)应用同一个阈值,必须先将它们标准化(Standardization,即 Z-score 转换),使其变为均值 0、标准差 1 的分布。

总结

在本文中,我们不仅重温了统计学中经典的 68-95-99.7 法则,更重要的是,我们通过 Python 这一强大的工具,从理论推导、可视化展示到实战异常检测,全方位地掌握了一项实用的数据分析技能。

关键要点回顾:

  • 68%, 95%, 99.7% 分别对应 1, 2, 3 个标准差范围。
  • 使用 scipy.stats.norm.cdf 可以精确计算概率,用于验证假设。
  • 在现实项目中,我们可以利用 $\mu \pm 3\sigma$ 作为自动检测异常值的基准线。
  • 代码优化时,优先使用 NumPy 的向量化操作替代 Python 循环。

我鼓励你在自己的数据集上尝试运行这些代码。看看你的数据是否符合正态分布?是否存在那些潜伏在 $3\sigma$ 之外的“黑天鹅”事件?统计学不仅仅是数字,它是我们理解世界不确定性的一盏明灯。希望这篇文章能帮助你在数据科学的学习之路上更进一步!

如果你想进一步探索,可以尝试修改代码中的均值和标准差参数,观察分布曲线的变化,或者尝试结合 Pandas 库直接读取 CSV 文件进行分析。祝编码愉快!

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。如需转载,请注明文章出处豆丁博客和来源网址。https://shluqu.cn/46568.html
点赞
0.00 平均评分 (0% 分数) - 0