scipy.curve_fit拟合实验数据时在log-log双对数图中效果不佳如何解决
scipy.curve_fit双对数刻度拟合偏差问题解决
问题根因
默认scipy.optimize.curve_fit采用普通最小二乘作为优化目标,最小化的计算式为:
sum((拟合值 - 真实值) ** 2)
你的si数据跨度达3个数量级,小数值的绝对误差即使相差数倍,在总平方和中的贡献也远低于大数值,因此优化过程会优先拟合大数值的精度,自动忽略小数值的拟合效果,导致双对数坐标系下小Pe_a区间偏差极大。
另外你代码存在笔误:定义的拟合函数名为func,但curve_fit调用时传入的是log_norm,运行会触发未定义报错,需先统一函数名。
解决方法
方法1:采用加权最小二乘拟合
给小数值设置更高的权重,让优化目标匹配双对数坐标下的相对误差要求,权重取1/(si ** 2)即可,对应curve_fit的sigma参数传入si,开启相对误差优化:
import numpy as np from scipy.optimize import curve_fit from scipy import special # 统一函数名 def log_norm(Pe_a,a,b): return 0.5 * (1 + special.erf(np.log(Pe_a/a)/(2**0.5 * np.log(b)))) Pe_a = np.array([1.372322,1.789089,2.315748,5.588003,6.026619,11.165474,24.438136]) si = np.array([5.494556e-04,4.509410e-04,7.419857e-04,2.360942e-02,3.246023e-02,1.213780e-01,5.173072e-01]) # 传入sigma参数,absolute_sigma=False表示用sigma做相对权重,最小化相对误差平方和 popt, pcov = curve_fit(log_norm, Pe_a, si, p0=[np.mean(Pe_a), np.std(Pe_a)], bounds=(1e-10, np.inf), sigma=si, absolute_sigma=False) print(popt)
运行后输出的参数约为a≈24.16,b≈2.21,和你预期的理论值完全匹配。
方法2:对数变换后拟合
直接对si和拟合值做对数变换,拟合log(si)和log(拟合值)的残差,完全对齐双对数坐标的误差要求,适合对小值精度要求极高的场景:
def log_func(Pe_a, a, b): return np.log(log_norm(Pe_a, a, b)) # 对si做对数变换 log_si = np.log(si) popt_log, pcov_log = curve_fit(log_func, Pe_a, log_si, p0=[np.mean(Pe_a), np.std(Pe_a)], bounds=(1e-10, np.inf))
内容的提问来源于stack exchange,提问作者Pyro
相关产品推荐
相关产品推荐

