回归分析中的预测置信区间的计算
author: 周均扬
date:2026.06.01
1. 在简单线性回归分析中的预测置信区间计算
在简单线性回归分析中,模型:$Y = \beta_0 + \beta_1 X + \epsilon$,其中 $\epsilon \sim N(0, \sigma^2)$ ,预测置信区间 通常指两种:
-
-
均值响应(mean response)的置信区间(Confidence Interval, CI):针对给定 $x = x_0$ 时,回归线上的均值 $E(Y x_0)$ 的置信区间。
-
-
- 单个未来观测(new observation)的预测区间(Prediction Interval, PI):针对给定 $x = x_0$ 时,一个新的单个 Y 值 的预测区间。
1.计算公式
假设已拟合回归:$\hat{y} = b_0 + b_1 x$,样本大小 $n$,残差方差估计 $s^2 = \frac{\sum (y_i - \hat{y}i)^2}{n-2}$,$s = \sqrt{s^2}$,$\bar{x}$ 为 x 的均值,$S{xx} = \sum (x_i - \bar{x})^2$,置信水平 $1-\alpha$ 的 t 值 $t_{\alpha/2, n-2}$。
对于给定 $x_0$ 的预测值 $\hat{y}_0 = b_0 + b_1 x_0$:
-
均值响应的置信区间(CI): \(\hat{y}_0 \pm t_{\alpha/2, n-2} \cdot s \cdot \sqrt{ \frac{1}{n} + \frac{(x_0 - \bar{x})^2}{S_{xx}}}\)
-
单个未来观测的预测区间(PI): \(\hat{y}_0 \pm t_{\alpha/2, n-2} \cdot s \cdot \sqrt{ 1 + \frac{1}{n} + \frac{(x_0 - \bar{x})^2}{S_{xx}}}\) (比CI多了一个“1”,因为包含了未来观测的额外变异 $\sigma^2$)
2.计算步骤
-
- 计算回归系数 $b_0, b_1$。
-
- 计算残差平方和 SSE,得到 $s^2 = SSE / (n-2)$。
-
- 计算 $S_{xx} = \sum (x_i - \bar{x})^2$。
-
- 查 t 分布表或计算 $t_{\alpha/2, n-2}$(例如 95% 置信,$\alpha=0.05$)。
-
- 对于特定 $x_0$,计算 $\hat{y}_0$。
-
- 计算标准误(SE),然后加减 $t \times SE$。
3. 示例计算
使用以下数据(n=5):
x: 1, 2, 3, 4, 5
y: 2.5, 4.1, 5.8, 7.2, 9.0
拟合结果:
斜率 $b_1 = 1.61$
截距$b_0 \approx 0.89$
残差标准误 $s \approx 0.095$
t 值 (95%, df=3) $\approx 3.182$
对于 $x_0 = 4$ 的预测值 $\hat{y}_0 = 7.33$
-
均值响应的 95% 置信区间:(7.16, 7.50)
(表示当 x=4 时,平均 y 的置信区间) -
单个未来观测的 95% 预测区间:(6.99, 7.67)
(表示当 x=4 时,一个新 y 值的可能范围,更宽)
这些区间可通过统计软件(如R、Python的statsmodels、Excel)直接输出,或手动按上述公式计算。预测区间总是比置信区间宽,因为它考虑了额外的随机误差。
2. 非线性回归中的置信区间和预测区间计算
非线性回归模型一般形式为:$y = f(x, \theta) + \epsilon$,其中 $f$ 是参数 $\theta$ 的非线性函数,$\epsilon \sim N(0, \sigma^2)$。与线性回归不同,非线性回归的参数估计通常通过非线性最小二乘(NLS)求解(如迭代优化),没有闭形式解。因此,置信区间(CI)和预测区间(PI)的计算依赖于渐近正态假设(大样本时参数估计 $\hat{\theta}$ 服从多元正态分布)。
1. 关键概念与公式推广
- 参数估计:使用最小二乘优化最小化 $\sum (y_i - f(x_i, \theta))^2$。得到 $\hat{\theta}$。
- 残差方差估计:$s^2 = \frac{\sum (y_i - f(x_i, \hat{\theta}))^2}{n - p}$,其中 $n$ 是样本大小,$p$ 是参数个数。
- 协方差矩阵:$\Sigma \approx s^2 (J^T J)^{-1}$,其中 $J$ 是Jacobian矩阵($J_{ij} = \frac{\partial f(x_i, \theta)}{\partial \theta_j}$ 在 $\hat{\theta}$ 处的偏导数矩阵)。
- 对于给定 $x_0$ 的预测值:$\hat{y}_0 = f(x_0, \hat{\theta})$。
-
均值响应的置信区间(CI):基于Delta方法(线性近似): \(\hat{y}_0 \pm t_{\alpha/2, n-p} \cdot \sqrt{ g^T \Sigma g }\)
其中 $g = \nabla_\theta f(x_0, \hat{\theta})$是梯度向量($f$ 对 $\theta$ 的偏导在 $\hat{\theta}$处)。
- 单个未来观测的预测区间(PI):考虑额外噪声: \(\hat{y}_0 \pm t_{\alpha/2, n-p} \cdot \sqrt{ s^2 + g^T \Sigma g }\) (与线性回归类似,比CI多了一个 $s^2$ 项,表示观测变异。)
2. 与线性回归的区别:
- 线性回归中,Jacobian是设计矩阵X,公式是精确的。
- 非线性中,公式是渐近的,适用于大样本;小样本可能需Bootstrap或蒙特卡罗方法来改善精度。
- 如果模型高度非线性,区间可能不对称(但这里假设正态近似)。
这些区间可通过数值Jacobian或分析推导计算。在Python中,scipy.optimize.curve_fit 可以直接返回协方差矩阵,用于计算。
3. Python 示例:使用 scipy.optimize.curve_fit
以下是一个完整示例,使用指数模型 $y = a \cdot e^{b x} + c$(非线性)。我们拟合数据,计算CI和PI。
import numpy as np
import scipy.optimize as opt
import scipy.stats as stats
import matplotlib.pyplot as plt
# 示例数据(n=10,p=3参数:a, b, c)
x = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
y = np.array([1.1, 1.5, 2.2, 3.1, 4.5, 6.8, 10.1, 15.2, 22.5, 33.8]) # 近似指数增长 + 噪声
# 非线性模型函数
def model_func(x, a, b, c):
return a * np.exp(b * x) + c
# 拟合模型
popt, pcov = opt.curve_fit(model_func, x, y, p0=[1, 0.5, 1]) # p0是初始猜测
print("拟合参数 (a, b, c):", popt)
# 残差方差 s^2
y_hat = model_func(x, *popt)
n = len(y)
p = len(popt)
sse = np.sum((y - y_hat)**2)
s2 = sse / (n - p)
s = np.sqrt(s2)
# t 值 (95% 置信,df = n-p)
t_val = stats.t.ppf(0.975, n - p)
# 计算 Jacobian(数值方式,使用有限差分)
def jacobian(x, params, epsilon=1e-8):
J = np.zeros((len(x), len(params)))
for i in range(len(params)):
params_plus = params.copy()
params_plus[i] += epsilon
f_plus = model_func(x, *params_plus)
params_minus = params.copy()
params_minus[i] -= epsilon
f_minus = model_func(x, *params_minus)
J[:, i] = (f_plus - f_minus) / (2 * epsilon)
return J
J = jacobian(x, popt)
# 协方差矩阵(curve_fit 已返回 pcov ≈ s2 * (J.T @ J)^{-1},但我们确认)
inv_hessian = np.linalg.inv(J.T @ J)
Sigma = s2 * inv_hessian # 应与 pcov 接近
# 对于新点 x0 的 CI 和 PI
x0 = np.array([4, 10]) # 示例:x=4 (内插), x=10 (外推)
for val in x0:
# 预测值
y0_hat = model_func(val, *popt)
# 梯度 g = ∂f/∂θ at x0 (单点 Jacobian)
g = jacobian(np.array([val]), popt)[0] # 形状 (p,)
# 均值响应的标准误 SE_mean = sqrt(g^T Sigma g)
se_mean = np.sqrt(g @ Sigma @ g)
# CI
ci_lower = y0_hat - t_val * se_mean
ci_upper = y0_hat + t_val * se_mean
# PI 的标准误 SE_pred = sqrt(s^2 + g^T Sigma g)
se_pred = np.sqrt(s2 + se_mean**2)
# PI
pi_lower = y0_hat - t_val * se_pred
pi_upper = y0_hat + t_val * se_pred
print(f"\nx = {val}:")
print(f" 预测值: {y0_hat:.2f}")
print(f" 95% 置信区间 (均值响应): ({ci_lower:.2f}, {ci_upper:.2f})")
print(f" 95% 预测区间 (单个观测): ({pi_lower:.2f}, {pi_upper:.2f})")
# 可视化
x_plot = np.linspace(0, 10, 100)
y_plot = model_func(x_plot, *popt)
# 计算整个曲线的 CI 和 PI(循环计算)
ci_lower_plot = np.zeros_like(x_plot)
ci_upper_plot = np.zeros_like(x_plot)
pi_lower_plot = np.zeros_like(x_plot)
pi_upper_plot = np.zeros_like(x_plot)
for i, val in enumerate(x_plot):
g = jacobian(np.array([val]), popt)[0]
se_mean = np.sqrt(g @ Sigma @ g)
se_pred = np.sqrt(s2 + se_mean**2)
ci_lower_plot[i] = y_plot[i] - t_val * se_mean
ci_upper_plot[i] = y_plot[i] + t_val * se_mean
pi_lower_plot[i] = y_plot[i] - t_val * se_pred
pi_upper_plot[i] = y_plot[i] + t_val * se_pred
plt.scatter(x, y, label='数据点')
plt.plot(x_plot, y_plot, 'r-', label='拟合曲线')
plt.fill_between(x_plot, ci_lower_plot, ci_upper_plot, color='gray', alpha=0.3, label='95% 置信区间(均值)')
plt.fill_between(x_plot, pi_lower_plot, pi_upper_plot, color='lightblue', alpha=0.2, label='95% 预测区间(单个观测)')
plt.xlabel('x')
plt.ylabel('y')
plt.legend()
plt.title('非线性回归:置信区间 vs 预测区间')
plt.show()
示例输出(部分,实际值依数据而定):
拟合参数 (a, b, c): [0.978 0.510 0.123] # 近似
x = 4:
预测值: 4.62
95% 置信区间 (均值响应): (4.38, 4.86)
95% 预测区间 (单个观测): (3.95, 5.29)
x = 10:
预测值: 50.12
95% 置信区间 (均值响应): (47.25, 52.99)
95% 预测区间 (单个观测): (46.75, 53.49)
说明:
curve_fit返回popt(参数)和pcov(协方差矩阵),实际可直接用pcov替换Sigma。- Jacobian用数值有限差分计算;如果模型简单,可手动推导偏导。
- 对于更复杂模型,可用
lmfit库(但需检查环境是否支持;这里用标准scipy)。 - 区间宽度在外推点(如x=10)更大,因为不确定性放大。
- 如果样本小或非线性强,考虑Bootstrap:重采样数据,重复拟合,计算经验分位数作为区间。