SciPy - ODR
SciPy - 正交距离回归(scipy.odr)
Section titled “SciPy - 正交距离回归(scipy.odr)”正交距离回归 (ODR) 是一种统计技术,用于在自变量(预测变量)和因变量(响应变量)都存在测量误差时,将模型拟合到数据。这与普通最小二乘法 (OLS) 回归形成对比,OLS 假设自变量已知精确,并且只最小化平方垂直距离之和(因变量的误差)。
在 ODR 中,目标是最小化从数据点到拟合曲线或曲面的平方正交(垂直)距离之和。这使得 ODR 在所有变量测量都存在不确定性的实验科学中特别有用。
scipy.odr 包提供了执行 ODR 的工具。
概念差异:OLS vs. ODR
Section titled “概念差异:OLS vs. ODR”想象将一条直线拟合到 (x, y) 数据点的散点图上:
- OLS(普通最小二乘法): 最小化从每个点 $(x_i, y_i)$ 到直线 $hat{y}_i = f(x_i)$ 的平方垂直距离之和。它假设 $x_i$ 无误差。
- 图示将显示点和垂直线,代表 OLS 最小化的误差。
- ODR(正交距离回归): 最小化从每个点 $(x_i, y_i)$ 到直线的平方垂直距离之和。它可以考虑 $x_i$ 中的误差 $delta_i$ 和 $y_i$ 中的误差 $epsilon_i$。
- 图示将显示点和垂直线,代表 ODR 最小化的误差。
当您有理由相信 X 的测量也存在不确定性,或者当您不想任意偏袒一个变量的误差而不是另一个变量的误差时,ODR 更适合使用。
scipy.odr 实现示例
Section titled “scipy.odr 实现示例”让我们通过将线性模型 $y = mx + c$ 拟合到 x 和 y 都可能存在误差的数据来演示 ODR。我们将基于二次关系生成一些合成数据,但尝试使用 ODR 对其进行线性模型拟合。如果基础模型未知或需要更简单的近似时,可能会出现这种情况。
import numpy as npimport matplotlib.pyplot as pltfrom scipy.odr import Model, Data, ODR, RealData
# 1. Define the model function for ODR# The function should take a tuple of parameters (beta) and the input x.# For a linear model y = m*x + c, beta = [m, c].# 1. 定义 ODR 的模型函数# 函数应接受一个参数元组 (beta) 和输入 x。# 对于线性模型 y = m*x + c,beta = [m, c]。def linear_func(beta, x): m, c = beta return m * x + c
# 2. Generate some sample data# Let's create data that roughly follows y = 0.5*x^2 + noise, but we'll try to fit a line.# 2. 生成一些样本数据# 创建大致遵循 y = 0.5*x^2 + noise 的数据,但我们尝试拟合一条直线。np.random.seed(0) # For reproducibility # 为了可重现性N_points = 20x_true = np.linspace(0, 5, N_points)y_true = 0.5 * x_true**2
# Add some noise to both x and y to simulate measurement errors# 向 x 和 y 都添加一些噪声以模拟测量误差x_observed = x_true + np.random.normal(0, 0.3, N_points)y_observed = y_true + np.random.normal(0, 1.0, N_points)
# (Optional) Specify standard deviations of errors if known (sx, sy)# If not known, ODR can estimate them or assume they are equal.# For this example, let's assume we don't know them perfectly.# (可选)如果已知误差的标准差 (sx, sy),则指定# 如果未知,ODR 可以估计它们或假设它们相等。# 对于此示例,假设我们对其了解不完全。# sx = np.full_like(x_observed, 0.3)# sy = np.full_like(y_observed, 1.0)# data = RealData(x_observed, y_observed, sx=sx, sy=sy)
# If errors are unknown or assumed to be weighted implicitly:# 如果误差未知或假定为隐式加权:data = RealData(x_observed, y_observed)
# 3. Create a Model object# We're fitting a linear function# 3. 创建一个 Model 对象# 我们正在拟合一个线性函数linear_model = Model(linear_func)
# 4. Set up ODR# beta0 provides initial guesses for the parameters [m, c].# 4. 设置 ODR# beta0 提供参数 [m, c] 的初始猜测。initial_guess_m = 1.0initial_guess_c = 0.5odr_instance = ODR(data, linear_model, beta0=[initial_guess_m, initial_guess_c])
# 5. Run the regression# 5. 运行回归odr_output = odr_instance.run()
# 6. Print the results# 6. 打印结果print("ODR Fit Results:") # ODR 拟合结果:odr_output.pprint() # Pretty print of results # 漂亮打印结果
# Extract fitted parameters# 提取拟合参数best_fit_params = odr_output.betam_fit, c_fit = best_fit_paramsprint(f"\nFitted slope (m): {m_fit:.4f}") # 拟合斜率 (m):print(f"Fitted intercept (c): {c_fit:.4f}") # 拟合截距 (c):
# Plot the results# 绘制结果plt.figure(figsize=(8, 6))plt.errorbar(x_observed, y_observed, xerr=0.3, yerr=1.0, fmt='o', label='Observed Data (with conceptual error bars)', capsize=3, alpha=0.6)# label='Observed Data (with conceptual error bars)' # 观测数据(带概念误差条)# capsize=3 # 误差条帽大小# alpha=0.6 # 透明度plt.plot(x_true, y_true, 'g--', label='True Underlying Quadratic Relation') # 真实的底层二次关系
# Plot the ODR fitted line# 绘制 ODR 拟合直线x_fit = np.linspace(min(x_observed), max(x_observed), 100)y_fit_odr = linear_func(best_fit_params, x_fit)plt.plot(x_fit, y_fit_odr, 'r-', label=f'ODR Linear Fit: y={m_fit:.2f}x + {c_fit:.2f}') # ODR 线性拟合:
plt.xlabel('X variable') # X 变量plt.ylabel('Y variable') # Y 变量plt.legend() # 图例plt.title('Orthogonal Distance Regression (ODR) Example') # 正交距离回归 (ODR) 示例plt.grid(True) # 网格# plt.show()# Description: This code generates synthetic data with errors in both x and y from an# underlying quadratic relationship. It then fits a linear model using ODR. The plot# shows the observed data points, the true quadratic curve, and the ODR fitted straight line.# The ODR line tries to minimize perpendicular distances to the points.# 描述:此代码生成在 x 和 y 中都包含误差的合成数据,这些数据来自# 底层的二次关系。然后使用 ODR 拟合线性模型。图表# 显示了观测数据点、真实的二次曲线以及 ODR 拟合的直线。# ODR 直线尝试最小化到点的垂直距离。odr_output.pprint() 的输出将包括:
Beta:估计的参数(例如,[m_fit, c_fit])。Beta Std Error:估计参数的标准误差。Beta Covariance:参数的协方差矩阵。Residual Variance:残差的方差。Inverse Condition #:问题数值稳定性的度量。Reason(s) for Halting:优化算法停止的原因(例如,收敛)。
pprint() 的示例(精简)输出:
Beta: [ 2.4591797 -1.12958544]Beta Std Error: [0.30591196 0.86113156]Beta Covariance: [[ 0.2266773 -0.59849207] [-0.59849207 1.7912691 ]]Residual Variance: 0.413024911864548Inverse Condition #: 0.0940618500416838Reason(s) for Halting: Sum of squares convergence这意味着 ODR 拟合找到一条直线 $y \approx 2.46x - 1.13$,作为考虑了 x 和 y 测量误差的噪声二次数据的最佳线性近似。
scipy.odr 的关键组成部分
Section titled “scipy.odr 的关键组成部分”Model(fcn, ...):定义要拟合的模型函数fcn(beta, x)。beta是模型参数的序列,x是自变量。Data(x, y, wd=None, we=None, ...)或RealData(x, y, sx=None, sy=None, ...):保存输入数据。当您有标准差 (sx,sy) 的估计值时,RealData很方便。如果未指定误差,可能会根据 ODR 设置进行估计或假定它们相等。ODR(data, model, beta0, ...):设置 ODR 问题的主类。beta0是参数的初始猜测。odr_instance.run():执行 ODR 算法。odr_output.beta:估计的最优参数。odr_output.sd_beta:估计参数的标准误差。
当自变量中的误差很大时,scipy.odr 模块在拟合方面非常强大。它支持显式、隐式、单变量和多变量模型。更多详细信息和高级配置,请参阅官方 SciPy ODR 文档。