You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何获取scipy.optimize.curve_fit迭代的参数及残差平方和

获取scipy curve_fit迭代过程的参数与残差平方和

你已经通过scipy.optimize.curve_fit完成函数拟合,但需要获取迭代过程中的参数值或对应残差平方和。由于curve_fit底层依赖的minpack库(leastsq函数)是Fortran实现,没有内置的迭代回调机制,无法直接从原函数获取这些信息,可通过以下两种方法实现需求:

方法一:改用scipy.optimize.minimize实现拟合并记录迭代

minimize支持自定义回调函数,可以在每次迭代时保存参数和对应残差平方和。具体步骤如下:

  1. 定义残差函数和目标函数(残差平方和)
  2. 定义回调函数,用于记录每次迭代的参数与残差平方和
  3. 调用minimize执行拟合,并提取记录的迭代信息

示例代码:

import math
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from scipy.optimize import minimize

data = pd.read_csv('at_5.csv', index_col='index')
x_data = np.array(data['x'])
y_data = np.array(data['y'])

# 定义拟合函数
def log_function(x, params):
    k, h, xo, a, ang, gamma = params
    return k * np.log(((((x - xo) - a * math.cos(ang)) ** 2) + (h - a * math.sin(ang)) ** 2) /
                        ((((x - xo) + a * math.cos(ang)) ** 2) + (h + a * math.sin(ang)) ** 2)) + gamma

# 定义残差平方和作为目标函数
def objective(params):
    y_pred = log_function(x_data, params)
    return np.sum((y_pred - y_data)**2)

# 存储迭代信息的列表
iter_records = []

# 回调函数:每次迭代时保存参数和残差平方和
def callback(params):
    res_sum = objective(params)
    iter_records.append({
        'params': params.copy(),
        'residual_sum': res_sum
    })

# 初始猜测值
guess = [75, 80, 550, 25, math.radians(10), 0]

# 调用minimize拟合,选择合适的优化器(比如L-BFGS-B)
result = minimize(objective, guess, method='L-BFGS-B', callback=callback, options={'maxiter': 10000})

# 输出最优参数
popt = result.x
print(f'''K = {popt[0]}, h = {popt[1]}, Xo = {popt[2]}, a = {popt[3]} and angle = {math.degrees(popt[4])}, gamma = {popt[5]}''')

# 查看迭代记录
print("迭代次数:", len(iter_records))
print("第一次迭代的参数与残差:", iter_records[0])
print("最后一次迭代的参数与残差:", iter_records[-1])

# 绘图
plt.scatter(x_data, y_data, c='blue', label='Data')
plt.plot(x_data, log_function(x_data, guess), color='green', label='Guess')
plt.plot(x_data, log_function(x_data, popt), color='red', label='Matched Data')
plt.xlabel('X')
plt.ylabel('V(X)')
plt.legend(loc='lower right')
plt.show()

方法二:通过全局变量记录函数调用时的参数与残差

如果坚持使用curve_fit,可以给拟合函数添加全局变量,每次函数被调用时记录参数和残差。注意:这种方法会记录curve_fit内部所有的函数调用(包括迭代过程中的试探性调用),需要后续筛选有效迭代步骤:

示例代码片段:

# 全局列表存储调用记录
call_records = []

def log_function(x, k, h, xo, a, ang, gamma):
    y_pred = k * np.log(((((x - xo) - a * math.cos(ang)) ** 2) + (h - a * math.sin(ang)) ** 2) /
                        ((((x - xo) + a * math.cos(ang)) ** 2) + (h + a * math.sin(ang)) ** 2)) + gamma
    # 计算当前参数对应的残差平方和
    res_sum = np.sum((y_pred - y_data)**2)
    call_records.append({
        'params': [k, h, xo, a, ang, gamma],
        'residual_sum': res_sum
    })
    return y_pred

# 后续调用curve_fit的代码不变
popt, cov = curve_fit(log_function, x_data, y_data, p0=guess, maxfev=10000)

# 查看记录(需自行筛选迭代步骤)
print("函数调用次数:", len(call_records))

关于scipy源码的说明

在scipy 1.11.2的_minpack_py.py中,curve_fit最终调用leastsq函数(位于同文件),而leastsq是对Fortran minpack库的封装,该库没有暴露迭代过程的回调接口,因此无法直接通过修改curve_fit的参数获取迭代信息,必须通过上述两种间接方法实现。

内容的提问来源于stack exchange,提问作者Mukilan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 11:23:19