Skip to content

统计度量

统计度量用单个数字概括数据,捕捉分散度、位置、形状和关联性。本章涵盖方差、标准差、四分位数、偏度、峰度、协方差、相关性和 z 分数,这是机器学习中探索性数据分析和特征工程的工具包。

  • 在前一章中,我们将矩作为一类汇总统计量介绍。这里我们展开从中衍生的实用工具:衡量分散度、位置、形状和关联性的度量。

  • 分散度回答了这样一个问题:数据有多分散?两个班级可以有相同的平均测试分数,但分散度却截然不同。

均值相同但分散度不同的两个分布

  • 狭窄的(蓝色)分布具有低方差:大多数值紧密聚集在均值周围。宽阔的(红色)分布具有高方差:值散布得更远。

  • 方差是每个数据点与均值距离平方的平均值。我们使用平方是为了避免正负偏差相互抵消。

\[\sigma^2 = \frac{1}{N} \sum_{i=1}^{N} (x_i - \mu)^2\]
  • 当处理样本(而非整个总体)时,我们除以 \(N - 1\) 而不是 \(N\)。这个修正(称为贝塞尔校正)考虑到样本往往会低估真实的变异性:
\[s^2 = \frac{1}{N-1} \sum_{i=1}^{N} (x_i - \bar{x})^2\]
  • 标准差是方差的平方根:\(\sigma = \sqrt{\sigma^2}\)。它将度量单位恢复到原始单位。如果你的数据以厘米为单位,方差是 cm\(^2\),但标准差又回到了厘米。

  • 平均绝对偏差 (MAD) 是一个更简单的替代方案。它不用平方,而是取每个偏差的绝对值:

\[\text{MAD} = \frac{1}{N} \sum_{i=1}^{N} |x_i - \mu|\]
  • MAD 比方差对异常值更稳健,因为它不会通过平方来放大大的偏差。但方差在数学上更方便(在证明和机器学习优化中它可以很好地分解)。

  • 位置回答了一个不同的问题:某个特定值相对于其余数据位于何处?

  • 四分位数将排序后的数据分成四个等份。Q1(第 25 百分位数)是 25% 的数据落在其下方的值。Q2 是中位数(第 50 百分位数)。Q3 是第 75 百分位数。

  • 四分位距 (IQR) 等于 \(Q3 - Q1\)。它捕捉了中间 50% 数据的分散度,忽略了极端值。

箱线图显示 Q1、中位数、Q3、IQR、须线和异常值

  • 箱线图是统计学中最有用的可视化图表之一。箱体从 Q1 延伸到 Q3,箱内的线是中位数,须线延伸到最远的非异常值,须线之外的点是异常值。

  • 百分位数推广了四分位数。\(p\) 百分位数是 \(p\%\) 的观测值落在其下方的值。Q1 是第 25 百分位数,中位数是第 50 百分位数,Q3 是第 75 百分位数。

  • z 分数告诉你一个值距离均值有多少个标准差:

\[z = \frac{x - \mu}{\sigma}\]
  • z 分数为 2 意味着该值高于均值 2 个标准差。z 分数为 \(-1.5\) 意味着低于均值 1.5 个标准差。这也称为标准化,在机器学习中广泛用于特征缩放,因为它可以将任何分布变换为均值为 0、标准差为 1 的分布。

  • 形状描述了一个分布除了中心和分散度之外的几何特征。

  • 偏度(前一章中的标准化三阶矩)衡量不对称性。像正态曲线这样完全对称的分布偏度为零。正偏度意味着右侧尾部更长(例如收入分布)。负偏度意味着左侧尾部更长(例如退休年龄)。

\[\text{偏度} = \frac{1}{N} \sum_{i=1}^{N} \left(\frac{x_i - \mu}{\sigma}\right)^3\]
  • 峰度(标准化的四阶矩)衡量尾部的沉重程度。正态分布的峰度为 3。尾部更重(更容易出现异常值)的分布峰度大于 3。
\[\text{峰度} = \frac{1}{N} \sum_{i=1}^{N} \left(\frac{x_i - \mu}{\sigma}\right)^4\]
  • 相关性衡量两个变量之间关系的强度和方向。它回答:当一个变量上升时,另一个变量倾向于上升、下降还是不变?

三个散点图显示正相关、无相关和负相关

  • 皮尔逊相关系数 (\(r\)) 衡量线性关联。它的范围从 \(-1\)(完全负相关)到 \(0\)(无相关)再到 \(+1\)(完全正相关)。
\[r = \frac{\sum_{i=1}^{N} (x_i - \bar{x})(y_i - \bar{y})}{\sqrt{\sum (x_i - \bar{x})^2} \cdot \sqrt{\sum (y_i - \bar{y})^2}}\]
  • 如果你回想第一章的点积,皮尔逊相关系数本质上就是均值中心化后的 \(\mathbf{x}\)\(\mathbf{y}\) 之间的余弦相似度。

  • 斯皮尔曼相关系数 (\(\rho\)) 衡量单调关联。它不直接使用原始值,而是先对它们进行排序,然后对排序后的秩计算皮尔逊相关系数。这使得它对异常值稳健,并且即使关系是非线性的(只要是单调递增或递减的)也能工作。

  • 几何平均数是当数值相乘(如增长率)时合适的平均值。如果你的投资分别增长 10%、20%、30%,平均增长因子不是这些比率的算术平均值。而是:

\[\bar{x}_{\text{几何}} = \left(\prod_{i=1}^{N} x_i\right)^{1/N}\]
  • 具体到增长率,先将百分比转换为因子(1.10、1.20、1.30),计算几何平均数,然后减去 1。

  • 指数移动平均 (EMA) 赋予最近的观测值更大的权重。与窗口内所有点等权重的简单移动平均不同,EMA 指数衰减:

\[\text{EMA}_t = \alpha \cdot x_t + (1 - \alpha) \cdot \text{EMA}_{t-1}\]
  • 平滑因子 \(\alpha\)(介于 0 和 1 之间)控制旧观测值失去影响的速度。\(\alpha\) 越大,对近期变化越敏感;\(\alpha\) 越小,越平滑。在机器学习中,EMA 用于像 Adam 这样的优化器以及批归一化中的运行统计量。

  • 异常值检测识别出与其他数据点异常远离的数据点。两种常见方法:

    • IQR 法:如果一个点低于 \(Q1 - 1.5 \times \text{IQR}\) 或高于 \(Q3 + 1.5 \times \text{IQR}\),则视为异常值。
    • z 分数法:如果一个点的 \(|z| > 3\)(距离均值 3 个标准差以上),则视为异常值。
  • IQR 法更为稳健,因为它不假定正态分布。当数据近似正态时,z 分数法效果很好,但当分布严重偏斜时可能失效。

编程任务(使用 CoLab 或 notebook)

  1. 计算一个数据集的方差、标准差和 MAD,并进行比较。观察当你添加一个极端异常值时会发生什么。

    import jax.numpy as jnp
    
    data = jnp.array([4, 8, 6, 5, 3, 7, 9, 5, 6, 7], dtype=jnp.float32)
    
    mean = jnp.mean(data)
    variance = jnp.var(data)
    std = jnp.std(data)
    mad = jnp.mean(jnp.abs(data - mean))
    
    print("原始数据:")
    print(f"  方差: {variance:.3f}, 标准差: {std:.3f}, MAD: {mad:.3f}")
    
    # 添加一个异常值并重新计算
    data_outlier = jnp.append(data, 100.0)
    mean2 = jnp.mean(data_outlier)
    print(f"\n包含异常值 (100):")
    print(f"  方差: {jnp.var(data_outlier):.3f}, 标准差: {jnp.std(data_outlier):.3f}, MAD: {jnp.mean(jnp.abs(data_outlier - mean2)):.3f}")
    

  2. 计算两个变量之间的皮尔逊相关系数和斯皮尔曼相关系数。尝试不同的关系。

    import jax
    import jax.numpy as jnp
    
    # 完美的线性关系
    x = jnp.array([1, 2, 3, 4, 5, 6, 7, 8], dtype=jnp.float32)
    y = 2 * x + 1  # 尝试改变这个!
    
    def pearson(a, b):
        a_c = a - jnp.mean(a)
        b_c = b - jnp.mean(b)
        return jnp.sum(a_c * b_c) / (jnp.sqrt(jnp.sum(a_c**2)) * jnp.sqrt(jnp.sum(b_c**2)))
    
    def spearman(a, b):
        rank_a = jnp.argsort(jnp.argsort(a)).astype(jnp.float32)
        rank_b = jnp.argsort(jnp.argsort(b)).astype(jnp.float32)
        return pearson(rank_a, rank_b)
    
    print(f"皮尔逊 r:  {pearson(x, y):.4f}")
    print(f"斯皮尔曼 ρ: {spearman(x, y):.4f}")
    

  3. 使用 IQR 和 z 分数两种方法实现异常值检测,然后在偏斜数据上比较它们的结果。

    import jax.numpy as jnp
    
    data = jnp.array([2, 3, 3, 4, 5, 5, 5, 6, 6, 7, 50], dtype=jnp.float32)
    
    # IQR 法
    q1, q3 = jnp.percentile(data, 25), jnp.percentile(data, 75)
    iqr = q3 - q1
    lower, upper = q1 - 1.5 * iqr, q3 + 1.5 * iqr
    iqr_outliers = data[(data < lower) | (data > upper)]
    print(f"IQR 边界: [{lower:.1f}, {upper:.1f}]")
    print(f"IQR 异常值: {iqr_outliers}")
    
    # z 分数法
    z_scores = (data - jnp.mean(data)) / jnp.std(data)
    z_outliers = data[jnp.abs(z_scores) > 3]
    print(f"\nz 分数: {z_scores}")
    print(f"z 分数异常值 (|z| > 3): {z_outliers}")
    

  4. 在带噪声的数据上计算并绘制不同平滑因子下的指数移动平均。

    import jax.numpy as jnp
    import matplotlib.pyplot as plt
    
    # 生成带噪声的数据
    key = __import__("jax").random.PRNGKey(0)
    noise = __import__("jax").random.normal(key, shape=(50,))
    signal = jnp.linspace(0, 5, 50) + noise
    
    def ema(data, alpha):
        result = jnp.zeros_like(data)
        result = result.at[0].set(data[0])
        for t in range(1, len(data)):
            result = result.at[t].set(alpha * data[t] + (1 - alpha) * result[t - 1])
        return result
    
    plt.figure(figsize=(10, 4))
    plt.plot(signal, "o", alpha=0.3, label="原始数据", color="#999")
    for alpha, color in [(0.1, "#e74c3c"), (0.3, "#3498db"), (0.7, "#27ae60")]:
        plt.plot(ema(signal, alpha), label=f"α={alpha}", color=color, linewidth=2)
    plt.legend()
    plt.title("不同平滑因子下的指数移动平均")
    plt.show()