【问题标题】:Fit a differential equation using scipy, getting "object too deep for desired array"使用 scipy 拟合微分方程,得到“对象对于所需数组来说太深”
【发布时间】:2021-09-23 07:55:41
【问题描述】:

我正在尝试将曲线拟合到微分方程。为了简单起见,我只是在这里做逻辑方程。我写了下面的代码,但我得到下面显示的错误。我不太确定自己做错了什么。

import numpy as np
import pandas as pd
import scipy.optimize as optim
from scipy.integrate import odeint

df_yeast = pd.DataFrame({'cd': [9.6, 18.3, 29., 47.2, 71.1, 119.1, 174.6, 257.3, 350.7, 441., 513.3, 559.7, 594.8, 629.4, 640.8, 651.1, 655.9, 659.6], 'td': np.arange(18)})

N0 = 1
parsic = [5, 2]

def logistic_de(t, N, r, K):
    return r*N*(1 - N/K)

def logistic_solution(t, r, K):
    return odeint(logistic_de, N0, t, (r, K))

params, _ = optim.curve_fit(logistic_solution, df_yeast['td'], df_yeast['cd'], p0=parsic);
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
ValueError: object too deep for desired array

---------------------------------------------------------------------------
error                                     Traceback (most recent call last)
<ipython-input-94-2a5a467cfa43> in <module>
----> 1 params, _ = optim.curve_fit(logistic_solution, df_yeast['td'], df_yeast['cd'], p0=parsic);

~/SageMath/local/lib/python3.9/site-packages/scipy/optimize/minpack.py in curve_fit(f, xdata, ydata, p0, sigma, absolute_sigma, check_finite, bounds, method, jac, **kwargs)
    782         # Remove full_output from kwargs, otherwise we're passing it in twice.
    783         return_full = kwargs.pop('full_output', False)
--> 784         res = leastsq(func, p0, Dfun=jac, full_output=1, **kwargs)
    785         popt, pcov, infodict, errmsg, ier = res
    786         ysize = len(infodict['fvec'])

~/SageMath/local/lib/python3.9/site-packages/scipy/optimize/minpack.py in leastsq(func, x0, args, Dfun, full_output, col_deriv, ftol, xtol, gtol, maxfev, epsfcn, factor, diag)
    420         if maxfev == 0:
    421             maxfev = 200*(n + 1)
--> 422         retval = _minpack._lmdif(func, x0, args, full_output, ftol, xtol,
    423                                  gtol, maxfev, epsfcn, factor, diag)
    424     else:

error: Result from function call is not a proper array of floats.

【问题讨论】:

  • 虽然curve_fit 尝试将输入转换为数组,但当您遇到此类问题时,请提前进行转换,例如df.to_numpy() 等,并确保生成的数组符合记录的要求,尤其是在维度和数据类型方面。
  • 就在前几天,一个类似的问题,stackoverflow.com/questions/69231675/…

标签: python scipy differential-equations


【解决方案1】:

@hpaulj 指出了来自logistic_solution 的返回值形状的问题,并表明修复可以消除您报告的错误。

但是,代码中还有另一个问题。该问题不会产生错误,但会导致您的测试问题(逻辑微分方程)的解不正确。默认情况下,odeint 期望计算微分方程的函数的 t 参数是 second 参数。更改logistic_de 的前两个参数的顺序,或者将参数tfirst=True 添加到您对odeint 的调用中。第二个选项更好一些,因为如果您决定尝试使用该功能而不是odeint,它将允许您使用logistic_descipy.integrate.solve_ivp

【讨论】:

  • 我在运行odeint 时没有遇到任何问题。问题是 logistic_solution 结果的维度与 1d ydata 相比 - curve_fit 是抱怨 too deep 数组的那个。 too deep 是特定的 scipy 错误消息,不会立即转换为 numpy 维度问题。
  • @hpaulj:啊,所以我指出的错误不是报告错误的来源。然而,这仍然是一个错误,所写的代码并没有解决逻辑方程!查看您的计算解决方案图。它在大约 t=15 时达到最大值,然后略有下降。逻辑微分方程的解不能做到这一点。尝试将tfirst=True 添加到odeint 的调用中。
【解决方案2】:

logistic_solution 的示例运行产生 (18,1) 结果:

In [268]: logistic_solution(df_yeast['td'], *parsic)
Out[268]: 
array([[ 1.00000000e+00],
       [ 2.66666671e+00],
       [ 4.33333337e+00],
       [ 1.00000004e+00],
       [-1.23333333e+01],
       [-4.06666666e+01],
       [-8.90000000e+01],
       [-1.62333333e+02],
       [-2.65666667e+02],
       [-4.04000000e+02],
       [-5.82333333e+02],
       [-8.05666667e+02],
       [-1.07900000e+03],
       [-1.40733333e+03],
       [-1.79566667e+03],
       [-2.24900000e+03],
       [-2.77233333e+03],
       [-3.37066667e+03]])
In [269]: _.shape
Out[269]: (18, 1)

y 的值是

In [281]: df_yeast['cd'].values.shape
Out[281]: (18,)

定义一个返回一维数组的替代函数:

In [282]: def foo(t,r,K):
     ...:     return logistic_solution(t,r,K).ravel()

这行得通:

In [283]: params, _ = optim.curve_fit(foo, df_yeast['td'], df_yeast['cd'], p0=parsic)
In [284]: params
Out[284]: array([16.65599815, 15.52779946])

测试params:

In [287]: logistic_solution(df_yeast['td'], *params)
Out[287]: 
array([[  1.        ],
       [  8.97044688],
       [ 31.45157847],
       [ 66.2980814 ],
       [111.36464226],
       [164.50594767],
       [223.5766842 ],
       [286.43153847],
       [350.92519706],
       [414.91234658],
       [476.24767362],
       [532.78586477],
       [582.38160664],
       [622.88958582],
       [652.1644889 ],
       [668.0610025 ],
       [668.43381319],
       [651.13760758]])
In [288]: df_yeast['cd'].values
Out[288]: 
array([  9.6,  18.3,  29. ,  47.2,  71.1, 119.1, 174.6, 257.3, 350.7,
       441. , 513.3, 559.7, 594.8, 629.4, 640.8, 651.1, 655.9, 659.6])

too deep 在此上下文中表示 2d 数组,当它应该是 1d 时,以便与 ydata 进行比较

ydata : array_like
    The dependent data, a length M array - nominally ``f(xdata, ...)``.

【讨论】:

  • 实际上这并不能正确解决逻辑方程。请参阅@Warren Weckesser 的答案 + cmets。但是,它确实解决了错误。所以谢谢你!
猜你喜欢
  • 2017-01-21
  • 2012-10-28
  • 1970-01-01
  • 1970-01-01
  • 2019-04-03
  • 2019-10-19
  • 1970-01-01
  • 2019-04-15
  • 2019-05-14
相关资源
最近更新 更多