前言:
在经历了之前三期的一维搜素算法之后,我们今天介绍一个利用目标函数二阶泰勒多项式的最优解作为函数的近似最优解的方法——牛顿切线法,又名抛物线法。
算法原理:
牛顿切线法利用目标函数二阶泰勒多项式的最优解作为函数的近似最优解,如果新的近似最优解满足计算精度,如在新的近似最优解的一阶导数为零,则终止计算,否则再将函数在新点展开成二阶泰勒展多项式,用新的泰勒多项式的最优解作为函数的近似最优解,如此迭代,直到导数为零或者其绝对值小于事先给定的精度ε为止。由于该方法可看成切线法求导函数的零点,因此被称为牛顿切线法。
对在
点二阶泰勒展开:
略去高阶项得:
两边对x求导:
令,得到
取:
最为新的迭代点,继续迭代,直到达到精度,这样就得到了函数f的一个驻点。
在一定条件下(如:),这个驻点是极小点。若f是二次函数,则一次迭代就可以得到极小点。
算法步骤:
步骤1:给定初始点ε>0,令k=1.
步骤2:计算
步骤3:若ε,停止,
,否则转步骤4.
步骤4:计算,令k=k+1,转步骤2.
例题分析:
下面我们通过一道例题来加深一下对算法的认识。
例题:试用Newton法求函数的最优解。(
,ε=
)
解:
算法代码:
'''
Newton算法
2023.10.8
'''
from sympy import *
x = symbols("x")
f = 2*x**3-12*x+9
# 一阶求导
first_grad = diff(f,x)
print("first_grad",first_grad)
# 二阶求导
second_grad = diff(first_grad,x)
print("second_grad",second_grad)
def run(x0,ε):
count = 1
x1=x0-first_grad.subs({x:x0})/second_grad.subs({x:x0})
while True:
if abs(first_grad.subs({x:x1}))> ε:
print("第{}次迭代".format(count))
x1 = x1 - first_grad.subs({x: x1}) / second_grad.subs({x: x1})
print("得到的新的x1为:%f" %x1)
count = count+1
continue
else:
print("{:.4}".format(x1))
break
return x1
run(x0=2.0,ε=0.01)
用该代码所运算的结果为:
first_grad 6*x**2 - 12
second_grad 12*x
第1次迭代
得到的新的x1为:1.416667
第2次迭代
得到的新的x1为:1.414216
1.414
总结:
该方法的优点是:收敛速度快,局部二阶收敛。但是于此同时,缺点也较为明显:须计算二阶导数,工作量大;对初始点要求高,要求初 始点离极小点不太远,否则有可能使极小化发散或收敛到非极小点;局部收敛。
(行文中若有纰漏,希望大家指正)