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

Python使用curve_fit拟合多元幂函数模型未达预期,求修正

修正幂函数拟合的问题

你的代码存在几个关键错误,导致拟合结果完全不符合预期,以下是具体修正步骤:

1. 模型函数定义错误

curve_fit要求模型函数的第一个参数是自变量,后续是待拟合的参数。你当前的函数把参数放在前面,还直接引用全局变量,完全不符合API要求。正确的函数应该接收自变量(qt、fs、ov)和拟合参数(a、b、c、d):

def func(x, a, b, c, d):
    qt, fs, ov = x  # 解包自变量
    return a * (qt ** b) * (fs ** c) * (ov ** d)

2. curve_fit调用参数错误

你当前调用curve_fit(func, Vs, d)是把Vs当成自变量、d当成因变量,和你目标拟合的Vs = a*(qt^b)*(fs^c)*(ov^d)完全无关。正确的做法是把qt、fs、ov作为自变量打包传入,Vs作为因变量:

# 打包自变量
xdata = (qt, fs, ov)
# 执行拟合
popt, pcov = curve_fit(func, xdata, Vs)

3. 幂函数拟合的收敛优化

由于你的自变量数值范围差异极大(比如fs从0.1到229.6,qt是几千级别),直接拟合幂函数容易导致拟合不收敛。可以先通过对数转换转成线性模型,得到初始参数估计,再传入curve_fit帮助收敛:

import numpy as np

# 对数转换,将幂函数转为线性模型:ln(Vs) = ln(a) + b*ln(qt) + c*ln(fs) + d*ln(ov)
ln_Vs = np.log(Vs)
ln_qt = np.log(qt)
ln_fs = np.log(fs)
ln_ov = np.log(ov)

# 构造线性回归的特征矩阵
X = np.column_stack((ln_qt, ln_fs, ln_ov))
y = ln_Vs

# 线性回归求初始参数
from sklearn.linear_model import LinearRegression
reg = LinearRegression()
reg.fit(X, y)

# 转换回原参数
initial_a = np.exp(reg.intercept_)
initial_b = reg.coef_[0]
initial_c = reg.coef_[1]
initial_d = reg.coef_[2]
p0 = [initial_a, initial_b, initial_c, initial_d]

# 用初始参数执行拟合
popt, pcov = curve_fit(func, xdata, Vs, p0=p0)

4. 修正绘图逻辑

你原来的绘图是把Vs和d数组关联,这和目标拟合无关。正确的绘图应该对比原始Vs和拟合得到的Vs_pred:

Vs_pred = func(xdata, *popt)

plt.scatter(range(len(Vs)), Vs, label="原始数据")
plt.scatter(range(len(Vs_pred)), Vs_pred, label="拟合数据")
plt.legend()
plt.show()

完整修正代码

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

# 原始数据
qt = [10867.073, 8074.986, 2208.366, 3066.566, 2945.326, 4795.766, 2249.813, 2018.3]
fs = [229.6, 17.4, 5.3, 0.1, 0.1, 0.1, 0.1, 0.1]     
ov = [19.159, 29.054, 37.620, 44.854, 51.721, 58.755, 65.622, 72.492]  
Vs = [149.787, 125.3962, 133.927, 110.047, 149.787, 137.809, 201.506, 154.925] 

# 定义正确的模型函数
def func(x, a, b, c, d):
    qt, fs, ov = x
    return a * (qt ** b) * (fs ** c) * (ov ** d)

# 对数转换获取初始参数
ln_Vs = np.log(Vs)
ln_qt = np.log(qt)
ln_fs = np.log(fs)
ln_ov = np.log(ov)

X = np.column_stack((ln_qt, ln_fs, ln_ov))
y = ln_Vs

reg = LinearRegression()
reg.fit(X, y)

initial_a = np.exp(reg.intercept_)
initial_b = reg.coef_[0]
initial_c = reg.coef_[1]
initial_d = reg.coef_[2]
p0 = [initial_a, initial_b, initial_c, initial_d]

# 打包自变量并执行拟合
xdata = (qt, fs, ov)
popt, pcov = curve_fit(func, xdata, Vs, p0=p0)

# 输出拟合参数
print(f"a: {popt[0]:.6f}, b: {popt[1]:.6f}, c: {popt[2]:.6f}, d: {popt[3]:.6f}")

# 计算拟合值并绘图
Vs_pred = func(xdata, *popt)

plt.figure(figsize=(10,6))
plt.scatter(range(len(Vs)), Vs, color='red', label="原始Vs数据")
plt.plot(range(len(Vs_pred)), Vs_pred, color='blue', label="拟合Vs曲线")
plt.xlabel("样本索引")
plt.ylabel("Vs值")
plt.legend()
plt.show()

额外注意点

  • 避免参数名和数据变量名冲突:你原来的代码里参数d和数据数组d重名,容易导致逻辑混乱,建议重命名参数(比如把参数d改成e)。
  • 如果你的实际需求是拟合d和其他变量的关系,需要重新明确目标方程,当前代码是基于你给出的Vs = a*(qt^b)*(fs^c)*(ov^d)修正的。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 22:48:34