如何为4PL曲线拟合添加1/y²权重优化低值拟合效果
四参数逻辑(4PL)曲线拟合低数值区域效果差的解决方法
我用以下代码实现四参数逻辑(4PL)曲线拟合与绘图,但低数值区域的拟合效果很差。查资料说这类问题可以通过添加1/y²权重解决,但我尝试给curve_fit加sigma=1/Y_data**2后,拟合效果反而更糟。
原代码:
from scipy.optimize import curve_fit import matplotlib.pyplot as plt def fourPL(x, A, B, C, D): return ((A-D) / (1.0 + np.power(x / C, B))) + D X_data = np.array([700,200,44,11,3,0.7,0.2,0]) Y_data = np.array([600000,140000,30000,8000,2100,800,500,60]) popt, pcov = curve_fit(fourPL, X_data, Y_data) fig, ax = plt.subplots() ax.scatter(X_data, Y_data, label='Data') X_curve = np.linspace(min(X_data[np.nonzero(X_data)]), max(X_data), 5000) Y_curve = fourPL(X_curve, *popt) ax.plot(X_curve, Y_curve) ax.set_xscale('log') ax.set_yscale('log') plt.show()
当前拟合效果如图:
问题原因与解决方法
问题出在权重的正确使用方式和4PL拟合对初始参数的敏感性上:
curve_fit的sigma参数代表数据点的标准差,内部权重计算是1/sigma²,所以要实现1/y²权重,应该直接传sigma=Y_data,而不是1/Y_data**2。- 4PL拟合如果不给初始参数,很容易陷入局部最优,尤其在对数坐标轴下,低数值区域的拟合会跑偏。
修改后的代码
import numpy as np from scipy.optimize import curve_fit import matplotlib.pyplot as plt def fourPL(x, A, B, C, D): return ((A - D) / (1.0 + np.power(x / C, B))) + D X_data = np.array([700,200,44,11,3,0.7,0.2,0]) Y_data = np.array([600000,140000,30000,8000,2100,800,500,60]) # 根据4PL的物理意义设置初始参数:A是最大Y值,D是最小Y值,C是非零X的中位数,B是斜率因子 initial_guess = [max(Y_data), 1, np.median(X_data[X_data>0]), min(Y_data)] # 使用sigma=Y_data等价于1/Y_data²权重,absolute_sigma=True确保权重不被归一化 popt, pcov = curve_fit(fourPL, X_data, Y_data, p0=initial_guess, sigma=Y_data, absolute_sigma=True) fig, ax = plt.subplots() ax.scatter(X_data, Y_data, label='原始数据') # 拟合曲线包含X=0的情况,覆盖全部数据范围 X_curve = np.linspace(0, max(X_data), 5000) Y_curve = fourPL(X_curve, *popt) ax.plot(X_curve, Y_curve, label='拟合曲线') ax.set_xscale('log') ax.set_yscale('log') ax.legend() plt.show()
关键修改点
- 补全numpy导入:原代码遗漏
import numpy as np,必须补上才能正常运行。 - 添加初始参数p0:根据4PL曲线的特性设置初始值,引导拟合算法收敛到全局最优解,避免低数值区域拟合失效。
- 正确设置权重:
sigma=Y_data对应1/Y_data²的权重,配合absolute_sigma=True保证权重计算符合预期。 - 扩展拟合曲线范围:把X轴范围从最小非零值扩展到0,让拟合曲线完全覆盖原始数据的X范围。
内容的提问来源于stack exchange,提问作者John Crow
相关产品推荐
相关产品推荐

