深入理解四分位距与四分位差:数据离散度的稳健度量

在数据分析和统计学中,我们经常不仅要关注数据的集中趋势(如平均值),还要深入了解数据的波动情况。数值偏离其平均值的程度,我们称之为离中趋势(或离散度)。虽然全距(极差)是最简单的离散度度量,但它极易受到极端值的影响。为了解决这个问题,我们通常采用更稳健的统计量。本文我们将深入探讨两个核心概念——四分位距四分位差,看看它们如何帮助我们更准确地理解数据分布。

为什么我们需要四分位距?

当我们面对一组数据时,全距仅考虑了最大值和最小值,这在数据分布均匀时是有效的。但在现实世界的数据集中,往往会存在异常值。例如,在分析用户收入时,个别亿万富翁的存在会极大地拉高全距,使得收入分布看起来比实际情况要波动大得多。

为了避免极值对全距产生的影响,我们可以使用四分位距这一度量指标。它关注的是数据中间 50% 的范围,即忽略了头部和尾部的极端数据,从而提供了一个关于数据“核心”波动的真实视角。

什么是四分位距?

四分位距(Interquartile Range, 简称 IQR) 是数据集中第三个四分位数(上四分位数 $Q3$)与第一个四分位数(下四分位数 $Q1$)之间的差值。换句话说,它告诉我们中间 50% 数据的跨度有多大。

数学表达

确定四分位距的公式如下:

Inter Quartile Range = Q3 - Q1

其中:

  • $Q_1$ (25th Percentile):数据集中有 25% 的数据小于或等于此值。
  • $Q_3$ (75th Percentile):数据集中有 75% 的数据小于或等于此值。

计算示例:手动推导

让我们通过一个具体的例子来理解计算过程。假设我们有以下一组未排序的数据:

数据集:150, 110, 200, 300, 180, 320

#### 第一步:排序

首先,我们必须将数据按升序排列。这是计算分位数的基础步骤,任何编程实现的第一步通常都是排序。

排序后:110, 150, 180, 200, 300, 320

这里数据项数 $N = 6$。

#### 第二步:计算 $Q1$ 和 $Q3$ 的位置

对于未分组数据,我们可以使用位置公式来定位四分位数。通常使用线性插值法来处理非整数位置。

计算 $Q_1$ 的位置:

$$ Position_{Q1} = \frac{N+1}{4} = \frac{6+1}{4} = 1.75 $$

这意味着 $Q_1$ 的值位于第 1 个数据点和第 2 个数据点之间,且更靠近第 2 个数据点(因为是 0.75)。

$$ Q1 = \text{Value}{1st} + 0.75 \times (\text{Value}{2nd} – \text{Value}{1st}) $$

$$ Q_1 = 110 + 0.75 \times (150 – 110) $$

$$ Q_1 = 110 + 30 = 140 $$

计算 $Q_3$ 的位置:

$$ Position_{Q3} = 3 \times \frac{N+1}{4} = 3 \times 1.75 = 5.25 $$

这意味着 $Q_3$ 位于第 5 个和第 6 个数据点之间,且非常靠近第 5 个数据点。

$$ Q3 = \text{Value}{5th} + 0.25 \times (\text{Value}{6th} – \text{Value}{5th}) $$

$$ Q_3 = 300 + 0.25 \times (320 – 300) $$

$$ Q_3 = 300 + 5 = 305 $$

#### 第三步:计算四分位距 (IQR)

现在我们有了 $Q1$ 和 $Q3$,计算 IQR 就变得非常简单:

$$ \text{Interquartile Range} = Q3 – Q1 = 305 – 140 = 165 $$

这告诉我们,该数据集中间 50% 的数值跨度为 165 个单位。

Python 实战:使用 Python 处理四分位距

在现代数据科学中,我们很少手动计算这些指标。Python 的 INLINECODE782bf9d7 和 INLINECODEbe5daba3 库提供了非常高效的方法来计算分位数。让我们看看如何在代码中实现上述逻辑。

方法一:使用 NumPy (基于线性插值)

NumPy 默认使用的线性插值方法与我们刚才的手动计算非常接近。

import numpy as np

# 定义数据集
data = [150, 110, 200, 300, 180, 320]

# 计算四分位数
# method=‘linear‘ 是默认值,类似于我们手算的插值法
q1 = np.percentile(data, 25, method=‘linear‘)
q3 = np.percentile(data, 75, method=‘linear‘)

iqr = q3 - q1

print(f"Q1 (下四分位数): {q1}")
print(f"Q3 (上四分位数): {q3}")
print(f"四分位距: {iqr}")

代码解析

  • np.percentile(data, 25) 直接计算出 25% 位置的数值。
  • 注意不同的库(如 numpy, pandas, scipy)对于分位数的插值算法可能有微小的默认差异,但在处理小数据集时,线性插值通常是最直观的。

方法二:使用 SciPy (统计学专用库)

SciPy 提供了专门的 iqr 函数,非常适合统计学家使用。

from scipy.stats import iqr

data = [150, 110, 200, 300, 180, 320]

# 自动计算 IQR
result = iqr(data, interpolation=‘linear‘)

print(f"SciPy 计算的四分位距: {result}")
# 为了完整性,我们也可以手动验证
q1, q3 = np.percentile(data, [25, 75])
print(f"验证: {q3 - q1}")

方法三:使用 Pandas (处理 DataFrame)

当你处理表格数据时,Pandas 是首选。它能自动忽略 NaN(缺失值),这在实际业务中非常重要。

import pandas as pd

# 创建一个包含缺失值的模拟数据集
df = pd.DataFrame({
    ‘Sales‘: [150, 110, 200, np.nan, 300, 180, 320, 1000] # 1000 是一个潜在的异常值
})

# describe() 方法可以快速查看统计摘要,包含 Q1 和 Q3
print("统计摘要:")
print(df[‘Sales‘].describe())

# 直接计算 IQR
# 这里的 interpolation 参数行为与 NumPy 类似
q1 = df[‘Sales‘].quantile(0.25)
q3 = df[‘Sales‘].quantile(0.75)
iqr_value = q3 - q1

print(f"
Pandas 计算结果 (忽略 NaN):")
print(f"IQR: {iqr_value}")

什么是四分位差?

虽然四分位距(IQR)很有用,但在某些情况下,我们希望得到的度量单位能与原始数据保持一致,或者需要一个关于“平均偏离”的指标。这时,我们引入四分位差的概念。

四分位差(Quartile Deviation,QD),也被称为半四分位距(Semi-Interquartile Range),是上四分位数($Q3$)与下四分位数($Q1$)之间差值的一半。

公式推导

$$ \text{Quartile Deviation} = \frac{Q3 – Q1}{2} $$

简单来说,如果你把中间 50% 的数据看作一个整体,四分位差就是这个整体的“半径”。它告诉我们,围绕中位数,数据大约平均偏离了多少。

计算示例

让我们继续使用之前的数据:110, 150, 180, 200, 300, 320。

我们已经知道:

  • $Q_1 = 140$
  • $Q_3 = 305$

计算四分位差:

$$ QD = \frac{305 – 140}{2} = \frac{165}{2} = 82.5 $$

这个数值比 IQR 更小,更直观地反映了数据围绕中心值的典型离散程度。

高级应用:四分位差系数

作为数据分析师,我们经常面临一个棘手的问题:如何比较两个完全不同事物的波动性?

例如,你想比较“一组身高的波动”和“一组体重的波动”。

  • 身高的单位是厘米,IQR 可能是 20 厘米。
  • 体重的单位是公斤,IQR 可能是 10 公斤。

直接比较 20 和 10 是没有意义的,因为单位不同。即使是同类数据,如果量级差异巨大(例如大公司的股价 vs 小公司的股价),直接比较 IQR 也会产生误导。

为了解决这个问题,我们需要一个相对的度量,这就是四分位差系数

公式

$$ \text{Coefficient of Quartile Deviation} = \frac{Q3 – Q1}{Q3 + Q1} $$

为什么用这个公式?

  • 无量纲化:分子是距离,分母也是距离(总和),单位相互抵消,剩下的纯比率。
  • 标准化:它将离散度表示为相对于四分位距总和的一个比例,这使得我们可以跨数据集进行比较。

计算示例

继续使用我们的数据集:

  • $Q_3 = 305$
  • $Q_1 = 140$

$$ \text{Coefficient} = \frac{305 – 140}{305 + 140} = \frac{165}{445} \approx 0.37 $$

这表明,中间 50% 的离散度约占其位置总和的 37%。如果另一组数据的这个系数是 0.5,我们就可以自信地说,另一组数据的相对波动性比当前这组要高。

检测异常值:IQR 的核心实战应用

除了描述数据的离散程度,四分位距在数据清洗中最著名的一个应用就是检测异常值。作为开发者,你需要掌握这个技巧来处理“脏数据”。

1.5 倍 IQR 规则

统计学中一个常见的经验法则是:任何数据点如果落在 $(Q1 – 1.5 \times IQR)$ 之下或 $(Q3 + 1.5 \times IQR)$ 之上,通常被视为潜在的异常值。

实战代码:异常值检测器

让我们编写一个 Python 函数来自动化这个过程。这是一个你在实际工作中可以直接复用的代码片段。

import numpy as np

def detect_outliers(data):
    """
    使用四分位距方法检测数据中的异常值。
    返回一个元组:(异常值列表, 清洗后的数据列表)
    """
    # 转换为 numpy array 方便计算
    data_arr = np.array(data)
    
    # 1. 计算 Q1, Q3 和 IQR
    q1 = np.percentile(data_arr, 25)
    q3 = np.percentile(data_arr, 75)
    iqr = q3 - q1
    
    # 2. 定义边界
    # 注意:这里的 1.5 是一个常用的标准,但在某些严格场景下可调整为 3
    lower_bound = q1 - (1.5 * iqr)
    upper_bound = q3 + (1.5 * iqr)
    
    print(f"数据统计:")
    print(f"Q1: {q1}, Q3: {q3}, IQR: {iqr}")
    print(f"异常值检测边界: [{lower_bound}, {upper_bound}]")
    
    # 3. 筛选异常值
    outliers = data_arr[(data_arr  upper_bound)]
    cleaned_data = data_arr[(data_arr >= lower_bound) & (data_arr <= upper_bound)]
    
    return outliers, cleaned_data

# --- 测试用例 ---
# 这里我们故意加入一个明显的离群点 (5000)
raw_data = [150, 110, 200, 300, 180, 320, 5000]

outliers, clean = detect_outliers(raw_data)

print(f"
发现异常值: {outliers}")
print(f"清洗后的数据: {clean}")

输出解析

在这个例子中,5000 显著高于上边界。该算法成功识别了它。在实际工程中,你可以选择直接删除这些异常值,或者对其进行标记以进行后续的人工审查。

常见错误与最佳实践

在你开始应用这些概念之前,我想分享几个我在开发过程中遇到过的“坑”。

1. 忽略小样本的偏差

问题:当数据量非常小(例如 $N < 5$)时,分位数可能会极其不稳定,甚至出现数学上的谬误。
建议:在小样本下计算 IQR 时,务必谨慎。如果可能,尝试使用 bootstrap 方法来估算置信区间,或者明确标注数据量不足。

2. 混淆分位数的定义

问题:NumPy 的默认 INLINECODEf4263fab 与 Excel 的 INLINECODE0ba0cdc9 函数算法不同,也与 Pandas 的默认行为可能存在微小差异。
建议:在跨平台(如 Excel 报表 vs Python 后端)对数时,务必确保两端的插值算法一致。通常在 Python 中指定 INLINECODE32ab88b6 或 INLINECODE039b0cdc 可以匹配大多数需求。

3. 只看 IQR 而不看分布图

问题:IQR 是一个单一数值,它掩盖了分布的形状。两个 IQR 相同的数据集,可能一个是对称的,一个是偏态的。
建议:始终结合箱线图来可视化 IQR。代码示例:

import matplotlib.pyplot as plt

# 生成对比数据
data_normal = np.random.normal(0, 1, 1000) # 正态分布
data_uniform = np.random.uniform(-2, 2, 1000) # 均匀分布

plt.figure(figsize=(8, 6))
plt.boxplot([data_normal, data_uniform], labels=[‘Normal Dist‘, ‘Uniform Dist‘])
plt.title(‘同 IQR 不同分布形态的可视化对比‘)
plt.ylabel(‘Values‘)
plt.show()

总结与后续步骤

在这篇文章中,我们一步步地深入探讨了从简单的全距到稳健的四分位距,再到相对的四分位差系数。我们不仅学习了数学公式,更重要的是,我们学会了如何使用 Python 代码来实现这些统计指标,并将其应用于异常值检测这一实际场景。

核心要点回顾:

  • 稳健性:四分位距(IQR)排除了极值影响,比全距更稳健。
  • 标准化:四分位差系数消除了单位和量纲的影响,使比较成为可能。
  • 实战:1.5 倍 IQR 规则是数据清洗中检测离群点的黄金法则。

接下来你可以做什么?

我建议你尝试以下步骤来巩固你的理解:

  • 动手实践:下载一份公开数据集(如 Kaggle 上的房价或房价数据),尝试计算 IQR 并清洗掉明显的异常值,观察这如何影响后续的回归模型精度。
  • 探索偏度:既然我们已经掌握了中位数和分位数,不妨进一步研究“偏度”和“峰度”,看看数据分布的“尾巴”对分析有何影响。
  • 深入可视化:尝试使用 Seaborn 库绘制小提琴图,它比箱线图能展示更多的分布细节。

希望这篇指南能帮助你更自信地处理数据离散度问题。数据分析的旅程才刚刚开始,掌握这些基础统计工具,将使你的代码更加健壮和准确。

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