1735 字
9 分钟
阅读量加载中...
回顾协方差含义,利用Python进行计算

背景#

虽然小编在大学时学习过《概率论与数理统计》课程,但是当时学的比较粗浅,没有真正理解协方差的概念,只是死记硬背记住了计算公式,后来每当阅读相关资料时,总是对协方差这个概念模糊不清,现在有了大模型这位不厌其烦的师者,可以借助其进行深入学习

在统计学中,协方差是一个基础又极其重要的概念,它衡量两个变量之间“共同变化”的倾向,是理解相关性、回归分析和主成分分析等方法的基石

本文会通过直观解释、数学定义、手算示例和 Python 代码,彻底搞懂协方差

协方差是什么#

简单来说,协方差衡量两个变量是“同向变化”还是“反向变化”

  • 如果 X 增大时,Y 也倾向于增大,协方差为
  • 如果 X 增大时,Y 反而倾向于减小,协方差为
  • 如果两者之间没有明显的线性关系,协方差会接近 0

“协”字就是指两个变量协同、共同变化的意思,它与方差(衡量单个变量自身的波动)形成对比——方差是偏差的平方的平均,协方差则是偏差的“交叉乘积”的平均

数学定义#

XY 为两个随机变量,它们的总体协方差定义为期望值:

$$ \mathrm{Cov}(X,Y) = E\big[(X-\mu_X)(Y-\mu_Y)\big] $$

其中 $\mu_X=E[X]$、$\mu_Y=E[Y]$ 是各自的期望。

实际工作中通常用样本去估计总体协方差,样本协方差公式为:

$$ s_{xy} = \frac{1}{n-1}\sum_{i=1}^{n}(x_i - \bar{x})(y_i - \bar{y}) $$

  • $x_i, y_i$ 是成对观测值
  • $\bar{x}, \bar{y}$ 是样本均值
  • $n$ 是样本量 分母用 $n-1$ 是为了得到总体协方差的无偏估计(和样本方差用 $n-1$ 的道理一样),如果数据本身就是总体,则分母用 $n$

深入理解“偏差叉积”#

公式的核心是 $(x_i - \bar{x})(y_i - \bar{y})$,常称它为偏差的交叉乘积,简称“偏差叉积”

“叉积”在这里不是向量外积(cross product),而是指把一个变量的偏差和另一个变量的偏差相乘,突出“交叉”的含义

与之对照:

  • 方差用的是偏差平方:$(x_i - \bar{x})^2$ ——自己乘自己
  • 协方差用的是偏差叉积:$(x_i - \bar{x})(y_i - \bar{y})$ ——一个乘另一个

这个乘积的正负号非常有信息量:

  • x 高于均值(偏差为正),y 也高于均值(偏差为正),乘积为
  • x 高于均值,而 y 低于均值(偏差为负),乘积为
  • 正负号反映了该数据点上两个变量相对于均值是同向偏离还是反向偏离

把所有点的偏差叉积加起来再平均,若大部分点同向偏离,总和为正,协方差大于零;若大部分反向偏离,总和为负,协方差小于零,所以,协方差就是“平均化的偏差叉积”

手算实例:完全负相关的例子#

用一组具体数据演示计算过程:

$$ x = [1, 2, 3, 4, 5], \quad y = [9, 8, 7, 6, 5] $$

第一步:计算均值 $$ \bar{x} = \frac{1+2+3+4+5}{5} = 3,\quad \bar{y} = \frac{9+8+7+6+5}{5} = 7 $$

第二步:计算每一点的偏差叉积

$x_i$$y_i$$x_i-\bar{x}$$y_i-\bar{y}$叉积 $(x_i-\bar{x})(y_i-\bar{y})$
19-2+2-4
28-1+1-1
37000
46+1-1-1
55+2-2-4

第三步:求和并平均 $$ \sum (x_i-\bar{x})(y_i-\bar{y}) = -4 -1 +0 -1 -4 = -10 $$ 样本协方差(除以 $n-1=4$): $$ s_{xy} = \frac{-10}{4} = -2.5 $$

结果为负值,说明 xy 存在负向变化关系,事实上这组数据完全满足 $y = 10 - x$,是完美的线性负相关

协方差的局限性与相关系数#

协方差的大小受变量测量尺度的影响,如果把 xy 的单位扩大100倍,协方差会放大 $100 \times 100 = 10000$ 倍,但两者关系的强弱完全没有改变

因此,不宜直接用协方差的大小来比较不同数据集的关联强度

为消除量纲影响,将协方差“标准化”,得到 皮尔逊相关系数 $r$: $$ r_{xy} = \frac{\mathrm{Cov}(X,Y)}{\sigma_X \sigma_Y} \quad (\text{总体}),\qquad r_{xy} = \frac{s_{xy}}{s_x s_y} \quad (\text{样本}) $$ 相关系数永远在 $[-1, 1]$ 之间,便于解读

对于上例,可以算出标准差 $s_x = s_y \approx 1.581$,相关系数 $r = \frac{-2.5}{1.581\times 1.581} = -1$,印证了完全负相关

利用 Python 计算协方差#

数据分析中当然不会每次都手算,下面介绍三种 Python 计算方法

1、纯 Python 手动实现#

直接按照公式编写函数,帮助理解计算过程。

def covariance(x, y, sample=True):
n = len(x)
mean_x = sum(x) / n
mean_y = sum(y) / n
cross_prod_sum = sum((xi - mean_x) * (yi - mean_y) for xi, yi in zip(x, y))
denom = n - 1 if sample else n
return cross_prod_sum / denom
x = [1, 2, 3, 4, 5]
y = [9, 8, 7, 6, 5]
print(covariance(x, y)) # 样本协方差,输出 -2.5
print(covariance(x, y, sample=False)) # 总体协方差,输出 -2.0

2、使用 NumPy#

numpy.cov 默认计算样本协方差矩阵,可通过参数 ddof 调整

import numpy as np
x = np.array([1, 2, 3, 4, 5])
y = np.array([9, 8, 7, 6, 5])
# 协方差矩阵,对角线为方差,非对角线为协方差
cov_matrix = np.cov(x, y)
print(cov_matrix)
# [[ 2.5 -2.5]
# [-2.5 2.5]]
# 提取 x 和 y 的协方差
cov_xy = np.cov(x, y)[0, 1] # -2.5
# 或者指定 ddof=0 得到总体协方差
cov_xy_pop = np.cov(x, y, ddof=0)[0, 1] # -2.0

注意:np.cov 要求输入是行排列,即每一行是一个变量,因此传入的两个数组会被视为两个变量

3、使用 Pandas#

如果用 Pandas 处理数据框,可以非常方便地计算协方差矩阵

import pandas as pd
df = pd.DataFrame({'x': [1, 2, 3, 4, 5],
'y': [9, 8, 7, 6, 5]})
# 协方差矩阵(默认样本协方差,分母 n-1)
print(df.cov())
# x y
# x 2.5 -2.5
# y -2.5 2.5
# 提取 x 和 y 的协方差
cov_xy = df['x'].cov(df['y']) # -2.5

Pandas 的 cov 方法也能通过参数调整,例如 df.cov(ddof=0) 得到总体协方差

总结#

  • 协方差衡量两个变量线性关系的方向:正、负或零
  • 它本质上是平均化的偏差叉积,叉积指两个变量偏差的交叉乘积
  • 协方差受量纲影响大,难以跨数据集比较强度,因此常标准化为相关系数
  • Python 中可通过手写公式、NumPy 的 cov 或 Pandas 的 cov 轻松计算协方差

掌握协方差,就打开了理解多元统计关系的大门,希望这篇文章能让你不仅“知其然”,更“知其所以然”

历史相关文章#


以上是自己实践中遇到的一些问题,分享出来供大家参考学习,欢迎关注微信公众号DataShare,不定期分享干货

微信公众号