解决Scipy报错:Result from function call is not a proper array of floats
常微分方程拟合报错:
Result from function call is not a proper array of floats. 原因及修复 问题描述
尝试用Scipy求解并拟合常微分方程 dc/dt = -k*c^α(k和α为待拟合参数,c为t时刻的解)时,运行代码出现错误:error: Result from function call is not a proper array of floats.。曾尝试对自定义函数输出使用np.ravel(),但又遇到error: 'int' object has no attribute ravel错误,还原初始代码后希望得到问题原因和修复方案。
初始代码
import numpy as np from scipy.integrate import odeint from scipy.optimize import curve_fit import matplotlib.pyplot as plt # Define the ODE function def ode_func(c, t, k, alpha): return -k*c**alpha # Define the initial condition and time points c0 = 1.73 t = np.linspace(1, 50, 1000) # Solve the ODE using scipy's odeint function c_true = odeint(ode_func, c0, t, args=(2, 2)) # Add some noise to the true solution np.random.seed(0) c_noisy = c_true + 0.1 * np.random.randn(*c_true.shape) # Use scipy.optimize.curve_fit to fit the noisy data popt, pcov = curve_fit(ode_func, t, c_noisy) plt.plot(t, odeint(ode_func, c0, t, args=(popt[0], popt[1])), 'r-', label='Fitted solution') #plotting the noisy solution plt.plot(t, c_noisy, 'o', label='Noisy solution') plt.legend() plt.show()
错误详情
--------------------------------------------------------------------------- ValueError Traceback (most recent call last) ValueError: object too deep for desired array --------------------------------------------------------------------------- error Traceback (most recent call last) Cell In[32], line 2 1 # Use scipy.optimize.curve_fit to fit the noisy data ----> 2 popt, pcov = curve_fit(ode_func, t, c_noisy) File c:\Python39\lib\site-packages\scipy\optimize\_minpack_py.py:859, in curve_fit(f, xdata, ydata, p0, sigma, absolute_sigma, check_finite, bounds, method, jac, full_output, **kwargs) 856 if ydata.size != 1 and n > ydata.size: 857 raise TypeError(f"The number of func parameters={n} must not" 858 f" exceed the number of data points={ydata.size}") --> 859 res = leastsq(func, p0, Dfun=jac, full_output=1, **kwargs) 860 popt, pcov, infodict, errmsg, ier = res 861 ysize = len(infodict['fvec']) File c:\Python39\lib\site-packages\scipy\optimize\_minpack_py.py:426, in leastsq(func, x0, args, Dfun, full_output, col_deriv, ftol, xtol, gtol, maxfev, epsfcn, factor, diag) 424 if maxfev == 0: 425 maxfev = 200*(n + 1) --> 426 retval = _minpack._lmdif(func, x0, args, full_output, ftol, xtol, 427 gtol, maxfev, epsfcn, factor, diag) 428 else: 429 if col_deriv: error: Result from function call is not a proper array of floats.
错误原因
- 函数参数顺序不匹配:
curve_fit要求拟合函数的第一个参数是自变量(这里是t),后续是待拟合参数;但你的ode_func是给odeint设计的,参数顺序是(c, t, k, alpha),完全不符合curve_fit的调用逻辑。 - 维度不匹配:
odeint返回的是二维数组(形状(1000,1)),而curve_fit期望因变量是一维数组,c_noisy的二维形状会导致维度错误。 - 函数功能错误:你直接把ODE的导数函数
ode_func传给curve_fit,但curve_fit需要的是输入t和参数,返回对应c值的函数,而不是返回导数的函数。
修复方案
- 封装一个适配
curve_fit的函数:输入t和待拟合参数k、alpha,内部调用odeint求解ODE,返回一维的解数组。 - 将
c_noisy展平为一维数组,匹配拟合函数的输出形状。 - 给
curve_fit提供初始参数猜测p0,帮助优化器更快收敛。
修复后的完整代码
import numpy as np from scipy.integrate import odeint from scipy.optimize import curve_fit import matplotlib.pyplot as plt # 定义ODE导数函数(给odeint用) def ode_func(c, t, k, alpha): return -k * c**alpha # 定义适配curve_fit的拟合函数:输入t和参数,返回ODE的解 def fit_func(t, k, alpha): c0 = 1.73 # 初始条件固定 # 求解ODE并展平为一维数组 return odeint(ode_func, c0, t, args=(k, alpha)).ravel() # 初始条件和时间点 c0 = 1.73 t = np.linspace(1, 50, 1000) # 生成真实解和带噪声的数据 np.random.seed(0) c_true = odeint(ode_func, c0, t, args=(2, 2)).ravel() c_noisy = c_true + 0.1 * np.random.randn(len(t)) # 拟合:提供初始参数猜测p0,避免优化器收敛失败 popt, pcov = curve_fit(fit_func, t, c_noisy, p0=[1, 1]) # 绘图展示 plt.plot(t, fit_func(t, *popt), 'r-', linewidth=2, label=f'拟合解 (k={popt[0]:.2f}, α={popt[1]:.2f})') plt.plot(t, c_noisy, 'o', markersize=2, label='带噪声数据') plt.xlabel('t') plt.ylabel('c') plt.legend() plt.show()
说明
fit_func是专门给curve_fit用的,参数顺序符合要求,并且返回一维数组。- 用
ravel()将odeint的二维输出转为一维,匹配c_noisy的形状。 - 添加
p0=[1,1]作为初始猜测,帮助curve_fit更快找到正确的参数值。
内容的提问来源于stack exchange,提问作者learner254
相关产品推荐
相关产品推荐

