别再死记公式了!用Python从零推导极大似然估计,5分钟搞懂核心思想
别再死记公式了!用Python从零推导极大似然估计,5分钟搞懂核心思想
统计学课本里那些密密麻麻的数学推导总是让人望而生畏?今天我们用Python代码和可视化图形,带你绕过复杂公式,直击 极大似然估计 (Maximum Likelihood Estimation, MLE)的核心思想。无需微积分基础,只要会写几行Python代码,你就能理解这个支撑现代机器学习的统计基石。
想象你是一位考古学家,在遗址中发现10枚古币,其中7枚是正面朝上。你会如何推测这批古币的"真实"正面概率?这就是MLE要解决的经典问题—— 通过观察到的数据,反推最可能产生这些数据的模型参数 。下面我们用一个正态分布的例子,分三步实现这个思想:
1. 模拟实验环境:生成观测数据
任何统计推断都始于数据。我们先设定一个"真实"的正态分布(均值μ=5,标准差σ=1),然后从中抽样生成模拟观测数据:
import numpy as np
import matplotlib.pyplot as plt
np.random.seed(42)
true_mu = 5 # 真实均值
true_sigma = 1 # 真实标准差
sample_size = 100 # 样本量
observations = np.random.normal(true_mu, true_sigma, sample_size)
用直方图可视化这些数据点,可以看到它们围绕5左右波动:
plt.hist(observations, bins=20, density=True, alpha=0.6)
plt.title('模拟观测数据分布')
plt.xlabel('数值')
plt.ylabel('频率')
plt.show()
注意:现实中我们只有观测数据,不知道真实的μ和σ。这里生成数据只是为了模拟实验场景。
2. 构建似然函数:量化参数可能性
似然函数L(θ)衡量的是: 在给定参数θ下,观察到当前数据的概率 。对于正态分布,其概率密度函数(PDF)为:
$$ f(x|\mu,\sigma) = \frac{1}{\sigma\sqrt{2\pi}} e^{-\frac{(x-\mu)^2}{2\sigma^2}} $$
因为各数据点独立,整体似然是所有数据点概率的乘积:
def likelihood(mu, sigma, data):
# 计算单个数据点的概率密度
single_prob = (1/(sigma * np.sqrt(2*np.pi))) * np.exp(-0.5*((data-mu)/sigma)**2)
# 返回所有数据点的联合概率(乘积)
return np.prod(single_prob)
但直接计算乘积会遇到 数值下溢 问题(大量小于1的数相乘结果趋近于0)。因此实践中使用 对数似然 (log-likelihood),将乘积转为求和:
def log_likelihood(mu, sigma, data):
n = len(data)
const = -n * np.log(sigma * np.sqrt(2*np.pi))
sum_sq = -np.sum((data - mu)**2) / (2 * sigma**2)
return const + sum_sq
3. 寻找最大似然:可视化参数空间
现在我们在μ的可能取值范围内(比如0到10),计算每个μ对应的对数似然值:
mu_candidates = np.linspace(0, 10, 100)
log_likelihoods = [log_likelihood(mu, true_sigma, observations) for mu in mu_candidates]
plt.plot(mu_candidates, log_likelihoods)
plt.axvline(x=true_mu, color='r', linestyle='--', label='真实均值')
plt.xlabel('候选μ值')
plt.ylabel('对数似然值')
plt.title('对数似然函数曲线')
plt.legend()
plt.show()
你会看到曲线在μ=5附近达到峰值——这正是MLE的核心理念: 选择使观测数据出现概率最大的参数值 。用代码找出精确的最大值点:
max_idx = np.argmax(log_likelihoods)
mle_mu = mu_candidates[max_idx]
print(f"极大似然估计的μ值: {mle_mu:.2f}")
运行结果通常会接近5(如4.85),与真实值非常接近。样本量越大,估计越准确。
4. 扩展到多参数估计:联合优化μ和σ
现实中σ也未知。我们可以扩展似然函数,同时优化两个参数:
from mpl_toolkits.mplot3d import Axes3D
# 生成参数网格
mu_grid = np.linspace(4, 6, 50)
sigma_grid = np.linspace(0.5, 1.5, 50)
M, S = np.meshgrid(mu_grid, sigma_grid)
# 计算每个(μ,σ)组合的对数似然
LL = np.array([[log_likelihood(m, s, observations)
for m in mu_grid] for s in sigma_grid])
# 3D可视化
fig = plt.figure(figsize=(10, 7))
ax = fig.add_subplot(111, projection='3d')
ax.plot_surface(M, S, LL, cmap='viridis')
ax.set_xlabel('μ')
ax.set_ylabel('σ')
ax.set_zlabel('对数似然')
plt.title('双参数对数似然函数曲面')
plt.show()
通过 scipy.optimize 可以自动找到最大值点:
from scipy.optimize import minimize
def neg_log_likelihood(params, data):
mu, sigma = params
return -log_likelihood(mu, sigma, data) # 最小化负对数似然
initial_guess = [4, 1] # 初始猜测
result = minimize(neg_log_likelihood, initial_guess, args=(observations,))
mle_mu, mle_sigma = result.x
print(f"MLE估计结果: μ={mle_mu:.2f}, σ={mle_sigma:.2f}")
5. 从数学到实践:MLE的应用陷阱
虽然MLE理论优美,但实际应用中需要注意:
- 样本量敏感性 :小样本下估计可能偏差较大
- 模型误设风险 :如果假设的分布模型与真实数据生成过程不符,结果将失真
- 计算复杂度 :对于复杂模型,似然函数可能难以优化
一个改进方案是 正则化 ,通过在似然函数中加入惩罚项防止过拟合:
def regularized_log_likelihood(params, data, lambda_reg=0.1):
mu, sigma = params
# 原始对数似然 + L2正则化项(惩罚大的σ值)
return log_likelihood(mu, sigma, data) - lambda_reg * sigma**2
最后分享一个实用技巧:在Python中,许多统计模型(如 statsmodels 库)已经内置了MLE实现。理解原理后,你可以直接调用:
import statsmodels.api as sm
model = sm.MLE(observations, model_function)
results = model.fit()
print(results.summary())
更多推荐



所有评论(0)