如何在Python中编写用于scipy.optimize.least_squares的误差函数
非线性拟合优化指南(针对你的代码场景)
看来你在非线性拟合调优上遇到了瓶颈,我结合你给出的代码片段和实际拟合中常见的问题,给你梳理几个能快速提升拟合效果的方向:
先把你的代码补全示意(方便后续操作)
你的温度数据有截断,我先补全常见的后续值,同时补上目标数据的占位,你替换成自己的实际数据即可:
import numpy as np import matplotlib.pyplot as plt from scipy.optimize import least_squares from scipy.optimize import curve_fit # 补全后的温度数据(根据截断部分推测) temperature = [38., 40., 42., 44., 46., 48., 50., 52., 54., 56., 58., 60., 62., 64., 66., 68., 70., 71.9, 73.81, 75.69, 77.6, 79.5, 81.4] # 替换成你的实际目标测量数据 y_data = []
一、先确保模型函数匹配数据的内在规律
非线性拟合的核心从来不是调参数,而是选对模型!如果你的模型和数据趋势完全不搭,再怎么调都没用:
- 第一步先画原始数据的散点图,看清趋势:
plt.scatter(temperature, y_data, color='darkorange', label='Raw Data') plt.xlabel('Temperature (°C)') plt.ylabel('Measured Value') plt.legend() plt.grid(alpha=0.3) plt.show() - 根据散点趋势选对应的模型:
- 如果是指数上升/下降:用Arrhenius类模型
def model(x, a, b): return a * np.exp(b * x) - 如果是饱和增长/下降:用Logistic模型
def model(x, a, b, c): return a / (1 + np.exp(-b*(x - c))) - 如果是有拐点的曲线:用二次/三次多项式
def model(x, a, b, c): return a*np.power(x,2) + b*x + c
- 如果是指数上升/下降:用Arrhenius类模型
二、给拟合参数一个靠谱的初始猜测
curve_fit和least_squares对初始参数非常敏感,瞎猜初始值很容易陷入局部最优:
- 手动根据数据估算初始值:比如饱和模型里,
a大概是数据的渐近最大值/最小值,c大概是拐点对应的温度,b是斜率的大致范围 - 示例(以饱和模型为例):
# 手动估算初始参数p0 p0 = [max(y_data), 0.1, np.median(temperature)] # 渐近值、斜率、拐点温度 # 执行拟合 popt, pcov = curve_fit(model, temperature, y_data, p0=p0)
三、用least_squares实现更灵活的拟合(可选)
如果你需要给参数加约束(比如参数必须为正),least_squares比curve_fit更实用:
# 自定义残差函数 def residuals(params, x, y): a, b, c = params return y - model(x, a, b, c) # 初始参数 x0 = [max(y_data), 0.1, np.median(temperature)] # 设置参数边界:比如a必须大于0,b必须大于0,c在温度范围内 bounds = ([0, 0, min(temperature)], [np.inf, np.inf, max(temperature)]) # 执行带约束的拟合 result = least_squares(residuals, x0, args=(temperature, y_data), bounds=bounds) popt = result.x # 拟合得到的最优参数
四、用量化指标评估拟合效果
别只靠眼睛看,用指标说话:
- 均方误差(MSE):值越小越好
mse = np.mean((model(temperature, *popt) - y_data)**2) - 决定系数R²:越接近1,拟合效果越好
ss_res = np.sum((y_data - model(temperature, *popt))**2) ss_tot = np.sum((y_data - np.mean(y_data))**2) r2 = 1 - (ss_res / ss_tot)
五、常见坑点排查
如果拟合结果还是很差,先检查这几点:
- 数据里有没有异常值?用3σ原则剔除掉偏离过大的点
- 模型是不是完全不符合数据趋势?比如数据是饱和的,但你用了线性模型
- 参数约束是不是太严?如果拟合后的参数卡在边界上,说明约束可能不合理或者初始值选得太差
内容的提问来源于stack exchange,提问作者dani reta
相关产品推荐
相关产品推荐

