如何在Python中使用curve_fit对loglog双对数数据进行直线拟合
双对数图幂律拟合代码调整方案
你当前使用curve_fit直接拟合原始幂律函数的逻辑,是在原始线性数值空间最小化残差平方和,大数值点的残差会主导拟合结果,因此在对数尺度下观察时,小数值区间的拟合偏差会非常明显,这就是你拟合效果不佳的核心原因。
调整方案
方案1:对数转换后做线性拟合(推荐,最适配双对数场景)
幂律关系y = a*x^b两边取常用对数后可得log10(y) = log10(a) + b*log10(x),属于标准线性关系,直接对对数化后的数据做线性拟合即可得到准确斜率,完全适配双对数坐标的拟合需求。
import numpy as np import matplotlib.pyplot as plt from scipy.stats import linregress fig = plt.figure(figsize=[7,7]) ax = plt.axes() ax.set_xscale("log") ax.set_yscale("log") y_val = unumpy.nominal_values(dn_dm) ax.errorbar(m, y_val , yerr= unumpy.std_devs(dn_dm), fmt='k.', label='Data') # 过滤y<=0的无效点(对数运算要求输入为正) mask = y_val > 0 log_m = np.log10(m[mask]) log_y = np.log10(y_val[mask]) # 线性拟合 res = linregress(log_m, log_y) b = res.slope a = 10 ** res.intercept print(f"拟合斜率为:{b:.3f}") newX = np.logspace(-.25, .5, base=10) ax.plot(newX, a * np.power(newX, b), 'r-', label=f'拟合线: 斜率={b:.3f}') ax.legend()
方案2:改进curve_fit的加权逻辑
如果你需要保留对原始幂律函数的拟合,可以给curve_fit添加权重,抵消大数值点的残差主导效应,最小化对数尺度下的残差:
from scipy.optimize import curve_fit # 过滤无效点 y_val = unumpy.nominal_values(dn_dm) mask = y_val > 0 m_filtered = m[mask] y_filtered = y_val[mask] def myExpFunc(x, a, b): return a * np.power(x, b) # 加权拟合,权重设置等价于最小化对数空间残差 popt, pcov = curve_fit(myExpFunc, m_filtered, y_filtered, sigma=y_filtered, absolute_sigma=True) newX = np.logspace(-.25, .5, base=10) ax.plot(newX, myExpFunc(newX, *popt), 'r-', label=f'拟合线: 斜率={popt[1]:.3f}')
拟合效果参考

内容的提问来源于stack exchange,提问作者Lewis Cooper
相关产品推荐
相关产品推荐

