最大似然估计与协方差正则化:从推导到实践
眼动坐标建模系列 · 第2篇
在上一篇里,我们学会了用二维高斯分布去描述眼动坐标的分布,知道它长得像个“椭圆山丘”,由均值向量 μ 和协方差矩阵 Σ 决定。理论看起来很漂亮,但当你真的拿到一堆数据,想去“学”出 μ 和 Σ 的时候,问题就来了:到底怎么学?凭感觉取平均行不行?怎么才能做到“最合理”?
这时候就要祭出统计学里的神器——最大似然估计(Maximum Likelihood Estimation, MLE)。
1. 从故事开始:为什么是“最大似然”?
假设你收集了很多用户的眼动坐标点,每个点记作 ( g_i = (x_i, y_i) )。你相信这些点是从某个高斯分布中“随机”产生的,只是你还不知道那个分布的 μ 和 Σ。换句话说,你知道公式的形状,但不知道参数。
于是你想:如果我已经看到这些样本了,那有没有办法找到一组 μ 和 Σ,让这些样本在这个模型下的“可能性”最大?——这就是最大似然估计的精神。
我们把这种“可能性”叫做似然(Likelihood):
L(μ,Σ)=P(观察到这些数据∣μ,Σ)=∏i=1Np(gi∣μ,Σ) L(\mu, \Sigma) = P(\text{观察到这些数据} | \mu, \Sigma) = \prod_{i=1}^N p(g_i | \mu, \Sigma) L(μ,Σ)=P(观察到这些数据∣μ,Σ)=i=1∏Np(gi∣μ,Σ)
也就是说,我们假设每个样本点都是独立的,那么总体似然就是每个点的概率密度的乘积。
我们要做的事情,就是找到能最大化这个乘积的 μ 和 Σ。
2. 一点直觉
想象一个很形象的比喻:
假设你有一张地图,地图上有个山丘,你不知道山丘的确切中心在哪,也不知道它的形状。现在你手上有一堆登山客的位置点,这些点大部分集中在某个区域。你希望画出一个“山丘模型”,让这些登山客尽可能都待在山丘高处。哪个山丘让这些点的高度总和最高,哪个就是最可能的分布。
最大似然估计就是干这事:让“数据”在“模型”中最舒服。
3. 数学推导(不跳步)
先写出二维高斯的概率密度:
p(gi∣μ,Σ)=1(2π)∣Σ∣1/2exp[−12(gi−μ)⊤Σ−1(gi−μ)] p(g_i | \mu, \Sigma) = \frac{1}{(2\pi) |\Sigma|^{1/2}} \exp\left[-\frac{1}{2}(g_i - \mu)^\top \Sigma^{-1} (g_i - \mu)\right] p(gi∣μ,Σ)=(2π)∣Σ∣1/21exp[−21(gi−μ)⊤Σ−1(gi−μ)]
总体似然就是所有样本乘起来:
L(μ,Σ)=∏i=1Np(gi∣μ,Σ) L(\mu, \Sigma) = \prod_{i=1}^N p(g_i | \mu, \Sigma) L(μ,Σ)=i=1∏Np(gi∣μ,Σ)
因为乘积很难直接最大化,我们取对数,变成更好处理的加法:
logL=−N2log∣2πΣ∣−12∑i=1N(gi−μ)⊤Σ−1(gi−μ) \log L = -\frac{N}{2}\log |2\pi \Sigma| - \frac{1}{2}\sum_{i=1}^N (g_i - \mu)^\top \Sigma^{-1} (g_i - \mu) logL=−2Nlog∣2πΣ∣−21i=1∑N(gi−μ)⊤Σ−1(gi−μ)
接下来,对 μ 求导。矩阵求导规则告诉我们:
∂∂μlogL=Σ−1∑i(gi−μ) \frac{\partial}{\partial \mu} \log L = \Sigma^{-1} \sum_i (g_i - \mu) ∂μ∂logL=Σ−1i∑(gi−μ)
令其为 0,可得:
μ^=1N∑i=1Ngi \hat{\mu} = \frac{1}{N} \sum_{i=1}^N g_i μ^=N1i=1∑Ngi
这个结果很直观:均值就是样本的平均值。
再对 Σ 求导,结果稍微复杂点,但最后可以得到:
Σ^=1N∑i=1N(gi−μ^)(gi−μ^)⊤ \hat{\Sigma} = \frac{1}{N} \sum_{i=1}^N (g_i - \hat{\mu})(g_i - \hat{\mu})^\top Σ^=N1i=1∑N(gi−μ^)(gi−μ^)⊤
这个就是 MLE 的协方差估计式。
4. 为什么除以 N 不是 N-1?
很多人第一次看到协方差公式时,都会疑惑为什么有时候分母是 N,有时候是 N-1。
其实两者都对,只是目标不一样:
- 用 N 是最大似然估计,能最大化似然;
- 用 N-1 是无偏估计,确保样本期望等于总体真实协方差。
在概率模型里,我们关心的是似然最大,所以用 N 没问题。但在统计描述中,我们想要估计“真实值”,这时候会选 N-1。
大部分机器学习库(比如 scikit-learn)在做概率建模时会默认用 N,但 numpy 的 np.cov
默认用 N-1。你在实现时要搞清楚目标是什么。
5. 实现 MLE:两行代码搞定
import numpy as npdef estimate_gaussian_params(X):mu = X.mean(axis=0)Xc = X - muSigma = (Xc.T @ Xc) / len(X) # MLE,用 Nreturn mu, Sigma