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

使用scipy.curve_fit拟合函数a x +b log((x-x0)/c)失败求助

解决scipy curve_fit拟合自定义对数函数的收敛问题

嘿,我来帮你搞定这个拟合失败的问题!你遇到的maxfev超限报错,主要是因为几个关键细节没处理到位,我一步步给你拆解并给出修复后的完整方案:

问题根源分析

  1. 函数定义域踩坑:你的拟合函数a*x + b*np.log((x-x0)/c)里,对数项要求(x-x0)/c > 0。如果初始参数猜得不对,很容易出现负数/零取对数的情况,函数返回NaN直接打断拟合流程。
  2. 参数拼写错误:你把maxfev(最大函数评估次数)写成了maxrev,这是个低级笔误,但会导致参数不生效。
  3. 缺少合理的初始参数猜测:curve_fit默认用全1的初始值,但你的函数有4个参数,和实际数据的参数范围偏差太大时,拟合算法根本找不到收敛方向。

修复后的完整代码

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

# 定义拟合函数,加入定义域防护避免NaN
def func(x, a, b, c, x0):
    arg = (x - x0)/c
    # 把小于等于0的输入替换成极小正数,防止对数报错
    arg = np.where(arg <= 0, 1e-10, arg)
    return a * x + b * np.log(arg)

# 读取数据
data1 = pd.read_csv(r'C:\Users\TanviPradhan\OneDrive - EFFECT Photonics\Desktop\CD581379_A-12469303362S__GAIN_DIODE_TEST__2021-08-03_16.57.36.txt',
                    skipinitialspace=True, comment="%")

# 提取x和y数据(转成numpy数组更稳定)
x = data1["InjectedCurrent(mA)"].values
y = data1["GAIN_X(V)"].values

# 拆分训练/测试集
train_x = x[:80]
train_y = y[:80]
test_x = x[80:]
test_y = y[80:]

# --------------------------
# 核心关键:给出贴合数据的初始参数猜测p0
# --------------------------
# 先估算线性部分的斜率a
a_guess = np.polyfit(x, y, 1)[0]
# x0必须小于所有x的最小值,这里取x最小值的90%
x0_guess = x.min() * 0.9
# c先设为1,后续拟合会自动调整
c_guess = 1.0
# b根据数据波动先给个小初始值
b_guess = 0.1

p0 = [a_guess, b_guess, c_guess, x0_guess]

# 添加参数边界约束(可选但推荐):确保x0小于x最小值,c为正
bounds = ([-np.inf, -np.inf, 1e-5, -np.inf], [np.inf, np.inf, np.inf, x.min() - 1e-5])

try:
    # 执行拟合,修正maxfev拼写,传入初始参数和边界
    params, pcov = curve_fit(func, x, y, p0=p0, maxfev=1000000, bounds=bounds)
    a_fit, b_fit, c_fit, x0_fit = params
    print(f"拟合完成!参数:a={a_fit:.4f}, b={b_fit:.4f}, c={c_fit:.4f}, x0={x0_fit:.4f}")

    # 生成拟合曲线用于可视化
    x_fit = np.linspace(x.min(), x.max(), 100)
    y_fit = func(x_fit, *params)

    # 绘图展示训练/测试数据和拟合结果
    fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(7,14))
    fig.suptitle('Wafer xx')

    # 训练数据子图
    ax1.scatter(train_x, train_y, label='Training Data')
    ax1.plot(x_fit, y_fit, 'r-', linewidth=2, label='Fitted Curve')
    ax1.set_xlabel("Injected Current (mA)")
    ax1.set_ylabel("GAIN_X(V)")
    ax1.set_title('Training Data & Fitted Curve')
    ax1.grid(True)
    ax1.legend()

    # 测试数据子图
    ax2.scatter(test_x, test_y, label='Testing Data')
    ax2.plot(x_fit, y_fit, 'r-', linewidth=2, label='Fitted Curve')
    ax2.set_xlabel("Injected Current (mA)")
    ax2.set_ylabel("GAIN_X(V)")
    ax2.set_title('Testing Data & Fitted Curve')
    ax2.grid(True)
    ax2.legend()

    plt.tight_layout()
    plt.show()
except Exception as e:
    print(f"拟合过程出错:{str(e)}")

额外小贴士

  • 如果还是不收敛,可以先拿前20-30个趋势最明显的数据点拟合,得到的参数再作为初始值拟合全量数据。
  • 检查你的数据里有没有异常值(比如突然跳变的点),异常值会严重干扰拟合,建议先做清洗。
  • 要是curve_fit还是搞不定,可以试试scipy.optimize.least_squares,它对复杂非线性函数的拟合稳定性更强。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 11:42:46