scipy.optimize.

newton#

scipy.optimize.newton(func, x0, fprime=None, args=(), tol=1.48e-08, maxiter=50, fprime2=None, x1=None, rtol=0.0, full_output=False, disp=True)[源]#

使用牛顿-拉弗森(或割线或哈雷)方法查找实函数或复函数的根。

给定附近的标量起始点 x0,找到标量值函数 func 的根。如果提供了 func 的导数 fprime,则使用牛顿-拉弗森方法,否则使用割线法。如果同时提供了 func 的二阶导数 fprime2,则使用哈雷方法。

如果 x0 是包含多个项的序列,newton 返回一个数组:从 x0 中每个(标量)起始点得到的函数根。在这种情况下,func 必须向量化,以返回与其第一个参数形状相同的序列或数组。如果给定 fprime (fprime2),则其返回值也必须具有相同的形状:每个元素是 func 相对于其唯一变量在其第一个参数的每个元素处求得的一阶(二阶)导数。

newton 用于查找单变量标量值函数的根。对于涉及多个变量的问题,请参阅 root

参数:
func可调用对象

要查找其根的函数。它必须是单变量函数,形式为 f(x,a,b,c...),其中 a,b,c... 是可以通过 args 参数传递的额外参数。

x0浮点数、序列或 ndarray

根的初始估计值,应在实际根附近。如果不是标量,则 func 必须向量化并返回与其第一个参数形状相同的序列或数组。

fprime可调用对象,可选

函数的导数,在可用且方便时提供。如果为 None(默认),则使用割线法。

args元组,可选

函数调用中要使用的额外参数。

tol浮点数,可选

根值的允许误差。如果 func 是复数值,建议使用更大的 tol,因为 x 的实部和虚部都对 |x - x0| 有贡献。

maxiter整数,可选

最大迭代次数。

fprime2可调用对象,可选

函数的二阶导数,在可用且方便时提供。如果为 None(默认),则使用普通的牛顿-拉弗森方法或割线法。如果不是 None,则使用哈雷方法。

x1浮点数,可选

根的另一个估计值,应在实际根附近。如果未提供 fprime 则使用。

rtol浮点数,可选

终止容差(相对)。

full_output布尔值,可选

如果 full_output 为 False(默认),则返回根。如果为 True 且 x0 是标量,则返回值为 (x, r),其中 x 是根,r 是一个 RootResults 对象。如果为 True 且 x0 不是标量,则返回值为 (x, converged, zero_der)(详见“返回值”部分)。

disp布尔值,可选

如果为 True,则在算法未收敛时引发 RuntimeError,错误消息包含迭代次数和当前函数值。否则,收敛状态将记录在 RootResults 返回对象中。如果 x0 不是标量,则忽略此参数。注意:这与显示无关,但为了向后兼容,`disp` 关键字不能重命名。

返回值:
root浮点数、序列或 ndarray

函数为零的估计位置。

rRootResults,可选

full_output=Truex0 是标量时存在。包含收敛信息。特别是,如果例程收敛,则 r.converged 为 True。

converged布尔值 ndarray,可选

full_output=Truex0 不是标量时存在。对于向量函数,指示哪些元素成功收敛。

zero_der布尔值 ndarray,可选

full_output=Truex0 不是标量时存在。对于向量函数,指示哪些元素的导数为零。

另请参阅

root_scalar

标量函数求根器的接口

root

多输入、多输出函数求根器的接口

备注

牛顿-拉弗森方法的收敛速度是二次的,哈雷方法是三次的,而割线法是亚二次的。这意味着如果函数行为良好,第 n 次迭代后估计根的实际误差大约是第 (n-1) 步后误差的平方(哈雷方法是立方)。然而,这里使用的停止准则是步长,并且不能保证找到了根。因此,应验证结果。更安全的算法有 brentq、brenth、ridder 和 bisect,但它们都要求根首先被限定在一个函数符号变化的区间内。在找到这样的区间后,brentq 算法建议用于一维问题的通用情况。

newton 与数组一起使用时,最适合以下类型的问题:

  • 所有初始猜测值 x0 到根的距离都相对相同。

  • 部分或所有额外参数 args 也是数组,以便可以同时解决一类类似问题。

  • 初始猜测值 x0 的大小大于 O(100) 个元素。否则,朴素的循环可能与向量方法一样好甚至更好。

示例

>>> import numpy as np
>>> import matplotlib.pyplot as plt
>>> from scipy import optimize
>>> def f(x):
...     return (x**3 - 1)  # only one real root at x = 1

未提供 fprime,使用割线法

>>> root = optimize.newton(f, 1.5)
>>> root
1.0000000000000016
>>> root = optimize.newton(f, 1.5, fprime2=lambda x: 6 * x)
>>> root
1.0000000000000016

仅提供 fprime,使用牛顿-拉弗森方法

>>> root = optimize.newton(f, 1.5, fprime=lambda x: 3 * x**2)
>>> root
1.0

同时提供 fprime2fprime,使用哈雷方法

>>> root = optimize.newton(f, 1.5, fprime=lambda x: 3 * x**2,
...                        fprime2=lambda x: 6 * x)
>>> root
1.0

当我们想为一组相关的起始值和/或函数参数寻找根时,可以将它们作为输入数组提供

>>> f = lambda x, a: x**3 - a
>>> fder = lambda x, a: 3 * x**2
>>> rng = np.random.default_rng()
>>> x = rng.standard_normal(100)
>>> a = np.arange(-50, 50)
>>> vec_res = optimize.newton(f, x, fprime=fder, args=(a, ), maxiter=200)

以上相当于在 for 循环中单独求解 (x, a) 中的每个值,只是速度更快

>>> loop_res = [optimize.newton(f, x0, fprime=fder, args=(a0,),
...                             maxiter=200)
...             for x0, a0 in zip(x, a)]
>>> np.allclose(vec_res, loop_res)
True

绘制所有 a 值的结果

>>> analytical_result = np.sign(a) * np.abs(a)**(1/3)
>>> fig, ax = plt.subplots()
>>> ax.plot(a, analytical_result, 'o')
>>> ax.plot(a, vec_res, '.')
>>> ax.set_xlabel('$a$')
>>> ax.set_ylabel('$x$ where $f(x, a)=0$')
>>> plt.show()
../../_images/scipy-optimize-newton-1.png