回归分析中的预测置信区间的计算

author: 周均扬

date:2026.06.01


1. 在简单线性回归分析中的预测置信区间计算

在简单线性回归分析中,模型:$Y = \beta_0 + \beta_1 X + \epsilon$,其中 $\epsilon \sim N(0, \sigma^2)$ ,预测置信区间 通常指两种:

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$:

2.计算步骤

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$

这些区间可通过统计软件(如R、Python的statsmodels、Excel)直接输出,或手动按上述公式计算。预测区间总是比置信区间宽,因为它考虑了额外的随机误差。

2. 非线性回归中的置信区间和预测区间计算

非线性回归模型一般形式为:$y = f(x, \theta) + \epsilon$,其中 $f$ 是参数 $\theta$ 的非线性函数,$\epsilon \sim N(0, \sigma^2)$。与线性回归不同,非线性回归的参数估计通常通过非线性最小二乘(NLS)求解(如迭代优化),没有闭形式解。因此,置信区间(CI)和预测区间(PI)的计算依赖于渐近正态假设(大样本时参数估计 $\hat{\theta}$ 服从多元正态分布)。

1. 关键概念与公式推广

2. 与线性回归的区别:

这些区间可通过数值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)

说明: