Scipy优化错误
Scipy optimize error
我有一个相当简单的 ODE 参数估计问题,我想在 Python 中解决。我一直在使用 odeint 函数来求解 ODE,并使用 scipy.optimize 库来查找参数。当我单独使用 odeint 函数时,我没有遇到任何问题,但是通过 scipy.optimize 它给我一个错误 RuntimeError: The array return by func must be one-dimensional, but got ndim=2.
我不认为它与 How to fix the error: The array return by func must be one-dimensional, but got ndim=2 重复,因为我可以独立 运行 odeint 求解器....
代码如下:
import numpy as np
from scipy.integrate import odeint
from scipy.optimize import minimize
init = [0,0]
t_end = 5
dt = 0.01
tspan = np.arange(0,t_end+dt,dt)
def my_fun(y,t,K):
if t<=0.07:
s = 2000
else:
s = 0
return np.array([s+3.6*(y[1]-y[0]) +K*y[0], 0.38*y[0]-0.48*y[1] +K*y[1]])
def solver(t,p2):
y_ode = odeint(my_fun,init,t,args = (p2,))
return y_ode
test = solver(tspan,0.01)
print(test)
y_real = solver(tspan, 0.1)
def err_fun(p):
return np.sum((y_real-solver(tspan,p))**2)
print(err_fun(0.01))
c0 = [0.2]
optim = minimize(err_fun,c0,method='Nelder-Mead')
问题是 minimize
调用 err_fun
的参数是长度为 1 的一维数组; err_fun
将其传递给 solver
,solver
将其传递给 odeint
,后者将其作为 K
参数传递给 my_fun
。当 K
是标量或长度为 1 的数组时,看一下 my_fun
输出形状的差异:
In [43]: my_fun([1, 2], 0, 0.05) # K is a scalar.
Out[43]: array([ 2.00365e+03, -4.80000e-01])
In [44]: my_fun([1, 2], 0, np.array([0.05])) # K is an array.
Out[44]:
array([[ 2.00365e+03],
[-4.80000e-01]])
当K
是长度为1的一维数组时,my_fun
returns是形状为(2, 1)的数组。这不是 odeint
所期望的。
要解决此问题,您必须将该数组转换为调用链中某处的标量。例如,您可以在 err_fun
中立即执行此操作,例如:
def err_fun(p):
if not np.isscalar(p):
p = p[0]
return np.sum((y_real-solver(tspan,p))**2)
当我这样做并且 运行 你的脚本时,代码有效。这是我得到的 optim
:
In [46]: optim
Out[46]:
final_simplex: (array([[0.1 ],
[0.09999512]]), array([2.95795174e-22, 4.03900365e-05]))
fun: 2.9579517415523713e-22
message: 'Optimization terminated successfully.'
nfev: 34
nit: 17
status: 0
success: True
x: array([0.1])
我有一个相当简单的 ODE 参数估计问题,我想在 Python 中解决。我一直在使用 odeint 函数来求解 ODE,并使用 scipy.optimize 库来查找参数。当我单独使用 odeint 函数时,我没有遇到任何问题,但是通过 scipy.optimize 它给我一个错误 RuntimeError: The array return by func must be one-dimensional, but got ndim=2.
我不认为它与 How to fix the error: The array return by func must be one-dimensional, but got ndim=2 重复,因为我可以独立 运行 odeint 求解器....
代码如下:
import numpy as np
from scipy.integrate import odeint
from scipy.optimize import minimize
init = [0,0]
t_end = 5
dt = 0.01
tspan = np.arange(0,t_end+dt,dt)
def my_fun(y,t,K):
if t<=0.07:
s = 2000
else:
s = 0
return np.array([s+3.6*(y[1]-y[0]) +K*y[0], 0.38*y[0]-0.48*y[1] +K*y[1]])
def solver(t,p2):
y_ode = odeint(my_fun,init,t,args = (p2,))
return y_ode
test = solver(tspan,0.01)
print(test)
y_real = solver(tspan, 0.1)
def err_fun(p):
return np.sum((y_real-solver(tspan,p))**2)
print(err_fun(0.01))
c0 = [0.2]
optim = minimize(err_fun,c0,method='Nelder-Mead')
问题是 minimize
调用 err_fun
的参数是长度为 1 的一维数组; err_fun
将其传递给 solver
,solver
将其传递给 odeint
,后者将其作为 K
参数传递给 my_fun
。当 K
是标量或长度为 1 的数组时,看一下 my_fun
输出形状的差异:
In [43]: my_fun([1, 2], 0, 0.05) # K is a scalar.
Out[43]: array([ 2.00365e+03, -4.80000e-01])
In [44]: my_fun([1, 2], 0, np.array([0.05])) # K is an array.
Out[44]:
array([[ 2.00365e+03],
[-4.80000e-01]])
当K
是长度为1的一维数组时,my_fun
returns是形状为(2, 1)的数组。这不是 odeint
所期望的。
要解决此问题,您必须将该数组转换为调用链中某处的标量。例如,您可以在 err_fun
中立即执行此操作,例如:
def err_fun(p):
if not np.isscalar(p):
p = p[0]
return np.sum((y_real-solver(tspan,p))**2)
当我这样做并且 运行 你的脚本时,代码有效。这是我得到的 optim
:
In [46]: optim
Out[46]:
final_simplex: (array([[0.1 ],
[0.09999512]]), array([2.95795174e-22, 4.03900365e-05]))
fun: 2.9579517415523713e-22
message: 'Optimization terminated successfully.'
nfev: 34
nit: 17
status: 0
success: True
x: array([0.1])