SciPy curve_fit参数协方差无法估计:Schott系数拟合求解
Schott色散函数拟合问题的解决思路
问题分析
用6个数据点拟合6参数的Schott逆函数时,出现协方差无法估计、参数全为inf的问题,核心原因有三个:
- 数据点数量刚好等于参数数量,拟合问题数值病态,微小波动就会导致参数发散
- 原函数包含开平方运算,拟合过程中内部多项式可能出现负值,引发
nan进而让优化崩溃 - 初始参数虽为Schott玻璃平均值,但可能和当前数据的最优解差距过大,优化器无法收敛
具体解决方法
1. 转换拟合形式,规避数值不稳定
把原函数两边平方,去掉开平方操作,转换成参数线性组合的形式:
原函数:$y = \sqrt{a0 + a1x² + a2x⁻² + a3x⁻⁴ + a4x⁻⁶ + a5x⁻⁸}$
平方后:$y² = a0 + a1x² + a2x⁻² + a3x⁻⁴ + a4x⁻⁶ + a5x⁻⁸$
这种形式可以用线性最小二乘法直接求解,也能避免开平方带来的数值问题。
代码示例:
import numpy as np from scipy.optimize import curve_fit # 转换后的无开平方拟合函数 def schott_squared(x, a0, a1, a2, a3, a4, a5): return a0 + a1 * x**2 + a2 * x**(-2) + a3 * x**(-4) + a4 * x**(-6) + a5 * x**(-8) x_data = np.array([0.65627, 0.64385, 0.58756, 0.54607, 0.48613, 0.47999]) y_data = np.array([1.7844818, 1.7858616, 1.7867687, 1.7899, 1.798498, 1.80231785]) y_squared = y_data ** 2 # 方法一:线性最小二乘法(最稳定) # 构造设计矩阵 X = np.column_stack([ np.ones_like(x_data), x_data**2, x_data**(-2), x_data**(-4), x_data**(-6), x_data**(-8) ]) params_lstsq, _, _, _ = np.linalg.lstsq(X, y_squared, rcond=None) print("线性拟合参数:", params_lstsq) # 方法二:用curve_fit拟合平方后的函数 # 替换成你手头的2000种Schott玻璃平均初始参数 init_params = [2.8, 0.01, 0.01, 0.0001, 0.00001, 0.000001] params_curvefit, _ = curve_fit(schott_squared, x_data, y_squared, p0=init_params) print("非线性拟合参数:", params_curvefit) # 验证拟合效果 y_fit = np.sqrt(schott_squared(x_data, *params_lstsq)) print("平均拟合误差:", np.mean((y_fit - y_data)**2))
2. 添加正则化约束
6个点拟合6参数是完全确定的,但数值上容易病态,加入L2正则化可以约束参数的量级,提升稳定性:
from scipy.optimize import minimize def loss_with_reg(params, x, y): y_pred_sq = schott_squared(x, *params) mse = np.mean((y_pred_sq - y**2)**2) # 正则强度可根据实际情况调整,1e-6是参考值 l2_reg = 1e-6 * np.sum(np.square(params)) return mse + l2_reg init_params = [2.8, 0.01, 0.01, 0.0001, 0.00001, 0.000001] result = minimize(loss_with_reg, init_params, args=(x_data, y_data)) print("正则化拟合参数:", result.x)
3. 统一特征量级
原函数中各项的量级差异极大:x²在0.23-0.43之间,x⁻⁸却能达到470左右,这种量级差会让优化器难以收敛。可以对输入特征做归一化处理,比如把x缩放为x / np.mean(x),或者对每一项特征做标准化,让所有特征的均值接近、方差一致。
4. 减少参数数量(可选)
如果高阶项(比如a4、a5)对当前玻璃的色散影响极小,可以固定这些参数为Schott平均值,只拟合前4个参数,让数据点数量多于参数数量,拟合会更稳定。
内容的提问来源于stack exchange,提问作者Amarth Gûl
相关产品推荐
相关产品推荐

