为何scipy.curve_fit无法拟合指定3D多变量曲线?
问题分析与解决方法
问题根源
你的代码中,x和y是完全相同的一维数组,计算z时每个点都满足x[i]=y[i]。代入目标函数后,当x=y时,y²*(...) -x²*(...) = 0,所有z值全为0。这种情况下,无论参数a和b取何值,函数在这些点上的输出都是0,拟合问题变成欠定状态,curve_fit无法找到参数的最优解,只能返回初始猜测值,同时协方差矩阵pcov全为无穷大。
解决步骤
- 生成网格数据:用
np.meshgrid创建所有x和y的组合点,确保大部分点满足x≠y,让z有足够的变化量。 - 扁平化数据:
curve_fit要求自变量是一维数组,需要将网格数据展平后传入。
修改后的代码
import numpy as np import matplotlib.pyplot as plt from scipy.optimize import curve_fit def func(X, a, b): x, y = X return y**2*(y**2/4 - a*y/3 + b/2) - x**2*(x**2/4 - a*x/3 + b/2) # 生成网格数据,创建所有x和y的组合 x = np.arange(0,5,0.1) y = np.arange(0,5,0.1) X, Y = np.meshgrid(x, y) # 真实参数 true_a = 6 true_b = 9 # 计算带噪声的z数据(模拟真实测量场景) Z = func((X, Y), true_a, true_b) + np.random.normal(0, 5, X.shape) # 扁平化数据,适配curve_fit的输入要求 x_flat = X.flatten() y_flat = Y.flatten() z_flat = Z.flatten() # 初始猜测 popt, pcov = curve_fit(func, [x_flat, y_flat], z_flat, p0=[10,8]) print("拟合参数:", popt) print("协方差矩阵:\n", pcov) print("a = ", popt[0], " +/- ", np.sqrt(pcov[0,0])) print("b = ", popt[1], " +/- ", np.sqrt(pcov[1,1])) # 绘制拟合结果与原始数据 ax = plt.axes(projection="3d") # 原始数据点 ax.scatter(X, Y, Z, alpha=0.3, label='原始数据') # 拟合曲面 Z_fit = func((X, Y), popt[0], popt[1]) ax.plot_surface(X, Y, Z_fit, cmap='viridis', alpha=0.5, label='拟合曲面') ax.legend() plt.show()
说明
- 加入少量高斯噪声模拟真实测量数据,即使不加噪声,只要
x≠y的点足够多,拟合也能正常工作。 - 扁平化后的数组包含所有
x和y的组合,函数输出z有足够变化,curve_fit可以通过梯度下降找到最优参数。
内容的提问来源于stack exchange,提问作者dan269
相关产品推荐
相关产品推荐

