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

如何在scipy curve_fit中实现过初始点且约束初始斜率的曲线拟合?

带初始点与指定初始斜率约束的曲线拟合方案

针对你需要拟合曲线同时满足过初始点和指定初始斜率的需求,以下是两种可行的实现方案,同时修正了原代码中拟合函数的冗余参数问题:


方案1:手动构造损失函数(兼容所有scipy版本)

通过scipy.optimize.minimize自定义损失函数,将数据点拟合误差、初始点约束误差、初始斜率约束误差整合为一个目标函数,通过权重控制约束的优先级。

代码实现

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

# 生成原始数据
x_data = np.linspace(1, 2)
p = [2, 3, -4, 1]
y_data = np.polyval(p, x_data)

# 约束参数
x0 = x_data[0]  # 初始点x坐标
y0 = y_data[0]  # 初始点y坐标
m0 = 8          # 指定初始斜率

# 修正后的拟合函数(原代码中参数b未被使用,此处补全)
def fit_func(x, a, b, c):
    return a * np.exp(x) + b * np.sin(x) + c

# 拟合函数的一阶导数(用于计算斜率)
def fit_deriv(x, a, b, c):
    return a * np.exp(x) + b * np.cos(x)

# 自定义损失函数
def loss(params):
    a, b, c = params
    # 普通数据点的加权拟合误差(对应原curve_fit的sigma设置)
    sigma = np.ones(len(x_data))
    sigma[0] = 0.01  # 放大初始点权重,强化过点约束
    data_error = np.sum(((fit_func(x_data, a, b, c) - y_data)/sigma)**2)
    # 初始斜率约束误差(用大权重确保约束优先满足)
    slope_error = 1000 * (fit_deriv(x0, a, b, c) - m0)**2
    # 初始点约束误差(可选,已通过sigma强化,此处进一步加固)
    point_error = 1000 * (fit_func(x0, a, b, c) - y0)**2
    return data_error + slope_error + point_error

# 求解最优参数
initial_guess = [1, 1, 0]  # 参数初始猜测值
result = minimize(loss, initial_guess)
popt = result.x

# 可视化结果
plt.plot(x_data, y_data, label='原始数据')
plt.plot(x_data, fit_func(x_data, *popt), label='拟合曲线')
# 标记初始点与指定斜率的切线
plt.scatter(x0, y0, color='red', zorder=5, label='初始点')
tangent_x = np.linspace(x0-0.1, x0+0.1)
tangent_y = y0 + m0*(tangent_x - x0)
plt.plot(tangent_x, tangent_y, '--', color='red', label=f'指定初始斜率m0={m0}')
plt.grid(True)
plt.legend()
plt.show()

方案2:使用curve_fit的内置约束(需scipy≥1.9.0)

从scipy 1.9.0开始,curve_fit支持通过constraints参数直接添加等式/不等式约束,无需手动构造损失函数,实现更简洁。

代码实现

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

# 生成原始数据
x_data = np.linspace(1, 2)
p = [2, 3, -4, 1]
y_data = np.polyval(p, x_data)

# 约束参数
x0 = x_data[0]
y0 = y_data[0]
m0 = 8

# 修正后的拟合函数
def fit_func(x, a, b, c):
    return a * np.exp(x) + b * np.sin(x) + c

# 拟合函数的一阶导数
def fit_deriv(x, a, b, c):
    return a * np.exp(x) + b * np.cos(x)

# 定义等式约束:初始点函数值等于y0,初始斜率等于m0
constraints = [
    {'type': 'eq', 'fun': lambda params: fit_func(x0, *params) - y0},
    {'type': 'eq', 'fun': lambda params: fit_deriv(x0, *params) - m0}
]

# 原sigma设置(可选,因已有等式约束,可省略)
sigma = np.ones(len(x_data))
sigma[0] = 0.01

# 带约束拟合
popt, pcov = curve_fit(
    fit_func, 
    x_data, 
    y_data, 
    sigma=sigma, 
    constraints=constraints, 
    p0=[1, 1, 0]
)

# 可视化结果
plt.plot(x_data, y_data, label='原始数据')
plt.plot(x_data, fit_func(x_data, *popt), label='拟合曲线')
plt.scatter(x0, y0, color='red', zorder=5)
tangent_x = np.linspace(x0-0.1, x0+0.1)
tangent_y = y0 + m0*(tangent_x - x0)
plt.plot(tangent_x, tangent_y, '--', color='red', label=f'指定初始斜率m0={m0}')
plt.grid(True)
plt.legend()
plt.show()

关键注意事项

  1. 修正原代码问题:原fit_func定义中包含参数b但未使用,导致拟合时b为冗余参数,已修正为b*np.sin(x)。
  2. 约束优先级:方案1中通过权重控制约束优先级,权重越大,约束越优先满足;方案2通过等式约束直接强制满足条件,无需权重设置。
  3. 版本兼容性:方案2需要scipy版本≥1.9.0,若版本较低,建议使用方案1。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 11:14:52