使用SciPy找到多维标量函数根的最佳方法

时间:2014-06-12 16:27:19

标签: python scipy

假设我有一个范围是标量但其域是向量的函数。例如:

def func(x):
  return x[0] + 1 + x[1]**2

找到此函数的 根的好方法是什么? scipy.optimize.fsolvescipy.optimize.root期望func返回一个向量(而不是标量),scipy.optimize.newton只接受标量参数。我可以将func重新定义为

def func(x):
  return [x[0] + 1 + x[1]**2, 0]

然后rootfsolve可以找到根,但是雅可比行列中的零意味着它不会总是做得很好。例如:

fsolve(func, array([0,2]))
=> array([-5,  2])

它只会改变第一个参数而不是第二个参数,这意味着它经常会找到一个远离的零点。


编辑:看起来func的以下重新定义效果更好:

def func(x):
  fx = x[0] + 1 + x[1]**2
  return [fx, fx]

fsolve(func, array([0,5]))
=>array([-16.27342781,   3.90812331])

所以它现在愿意改变这两个参数。但代码仍然有点难看。

2 个答案:

答案 0 :(得分:1)

您是否尝试使用fmin最小化函数的绝对值? 例如:

>>> import scipy.optimize as op
>>> import numpy as np

>>> def func(x):
>>>     return x[0] + 1 + x[1]**2
>>> func1 = lambda x: np.abs(func(x))

>>> tmp = op.fmin(func1, [10000., 10000.])
>>> func(tmp)
0.0
>>> print tmp
[-8346.12025122    91.35162971]

答案 1 :(得分:1)

因为 - 对于我的问题 - 我有一个很好的初始猜测和非疯狂的功能,牛顿的方法效果很好。对于标量,多维函数,牛顿方法变为:

equation

这是一个粗略的代码示例:

def func(x): #the function to find a root of
  return x[0] + 1 + x[1]**2

def dfunc(x): #the gradient of that function
  return array([1, 2*x[1]])

def newtRoot(x0, func, dfunc):
  x = array(x0)
  for n in xrange(100): # do at most 100 iterations
    f  = func(x)
    df = dfunc(x)

    if abs(f) < 1e-6: # exit function if we're close enough
      break

    x = x - df*f/norm(df)**2 # update guess
  return x

使用中:

nsolve([0,2],func,dfunc)
=> array([-1.0052546 ,  0.07248865])

func([-1.0052546 ,  0.07248865])
=> 4.3788225025098715e-09

还不错!当然,这个功能很粗糙,但你明白了。它也不适用于“棘手”的功能,或者你没有良好的开始猜测。我想我会使用这样的东西,但如果牛顿的方法不收敛,那么我会回到fsolveroot