一元和多元函数求极值(Python)-牛顿法

1. 引言

    我们在中学的时候学过一元二次函数,求解时引入一个求根公式,代入公式就可以得到不同的根,假如想计算一个高次方程的解,我们还能推导出求根公式吗?
    伽罗瓦在群论中证实,五次及以上多项式方程没有显示表达的求根公式,但是科学研究(例如行星轨道计算)中还是有很多求解高次方程的真实需求。既然得不到明确的求根公式,我们可以用迭代的办法来不断逼近真实的解。
    多项式方程求解的问题实际上可以看成是函数求极值,假如我们对f'(x)=0的求解得到驻点,将驻点代入f(x)就可以计算出函数的极值。显然低次方程的求解可以用求根公式精确计算x的值,但是高次方程的求解就要用逼近的思路比如梯度下降法、最速下降法、牛顿法等。本文主要讨论牛顿法和使用python对一元函数和多元函数求极值。

2. 牛顿法基本原理

2.1. 一元函数牛顿法

    假如函数f(x)是一个一元函数,使用泰勒公式二阶近似可以得到

f(x)\approx f(x_0)+f'(x_0)(x-x_0)+\frac{1}{2}f''(x_0)(x-x_0)^2

    一元函数取极值的条件是f'(x)=0,两端分别求导(下式约等号写作等号)得到

f'(x)=f(x_0)+f''(x_0)(x-x_0)=0

    整理出x的迭代公式

x = x_0-\frac{f'(x_0)}{f''(x_0)}

    进一步写出迭代关系表达式,得到

x_{n+1}=x_n-\frac{f'(x_n)}{f''(x_n)}

    因为牛顿法的迭代关系是根据要求解极值函数的导数图像在该点的斜率进行迭代,因此没有没有步长的概念,在哪一点得到极值仅仅依靠迭代的步数。相应的,迭代的次数越多越接近极值点。
    上述在介绍了抽象的公式之后,我们来看这样一个小例子,已知一个函数f(x)=x^6+x,在没有其他约束条件求f(x)的极值。
    在用牛顿法计算极值之前,使用软件绘制f(x)的图像,用肉眼粗略的观测一下极值在哪里,可以帮助我们在后续计算中检验正确与否。

image.png

    首先,需要给一个初始值x_0=10,这是要开始进行迭代的位置;
    然后,计算初始位置的一阶导数和二阶导数值,f'(10)f''(10)
    其次,代入迭代公式x_{1}=x_0-\frac{f'(x_0)}{f''(x_0)};
    最后,将得到的第一次迭代的值x_1重复上述两个步骤,得到x_2x_3、···x_n,停止条件为所设定的迭代步数。

2.2. 一元函数牛顿法的python程序

from sympy import *
# step为迭代步数,x0为初始位置,obj为要求极值的函数
def newtons(step, x0, obj):
    i = 1 # 记录迭代次数的变量
    x0 = float(x0) # 浮点数计算更快
    obj_deri = diff(obj, x) # 定义一阶导数,对应上述公式
    obj_sec_deri = diff(obj, x, 2) # 定义二阶导数,对应上述公式
    while i <= step:
        if i == 1:
            # 第一次迭代的更新公式
            xnew = x0 - (obj_deri.subs(x, x0)/obj_sec_deri.subs(x, x0))
            print('迭代第%d次:%.5f' %(i, xnew))
            i = i + 1
        else:
            #后续迭代的更新公式
            xnew = xnew - (obj_deri.subs(x, xnew)/obj_sec_deri.subs(x, xnew))
            print('迭代第%d次:%.5f' % (i, xnew))
            i = i + 1
    return xnew
x = symbols("x") # x为字符变量
result = newtons(50, 10, x**6+x)
print('最佳迭代的位置:%.5f' %result)

    运行程序结果如下:

迭代第1次:8.00000
迭代第2次:6.39999
迭代第3次:5.11997
迭代第4次:4.09593
迭代第5次:3.27662
迭代第6次:2.62101
迭代第7次:2.09610
迭代第8次:1.67515
迭代第9次:1.33589
迭代第10次:1.05825
迭代第11次:0.82002
迭代第12次:0.58229
迭代第13次:0.17590
迭代第14次:-34.68063
迭代第15次:-27.74450
迭代第16次:-22.19560
迭代第17次:-17.75648
迭代第18次:-14.20519
迭代第19次:-11.36415
迭代第20次:-9.09132
迭代第21次:-7.27306
迭代第22次:-5.81846
迭代第23次:-4.65480
迭代第24次:-3.72391
迭代第25次:-2.97930
迭代第26次:-2.38386
迭代第27次:-1.90812
迭代第28次:-1.52901
迭代第29次:-1.22931
迭代第30次:-0.99804
迭代第31次:-0.83203
迭代第32次:-0.73518
迭代第33次:-0.70225
迭代第34次:-0.69886
迭代第35次:-0.69883
迭代第36次:-0.69883
迭代第37次:-0.69883
迭代第38次:-0.69883
迭代第39次:-0.69883
迭代第40次:-0.69883
迭代第41次:-0.69883
迭代第42次:-0.69883
迭代第43次:-0.69883
迭代第44次:-0.69883
迭代第45次:-0.69883
迭代第46次:-0.69883
迭代第47次:-0.69883
迭代第48次:-0.69883
迭代第49次:-0.69883
迭代第50次:-0.69883
最佳迭代的位置:-0.69883

Process finished with exit code 0

    函数的极值点为-0.69883,与我们之前绘制的图像观测值一致。

2.3. 多元函数牛顿法

    多元函数用牛顿法求极值的思路依然采用泰勒公式近似展开,只不过这里的X为向量形式,假设f(X)为二元函数:

f(X)\approx f(X^{(0)}) +\nabla f(X^{(0)})^T(X-X^{(0)}) + \frac{1}{2}(X-X^{(0)})^T\nabla^2f(X^{(0)})(X-X^{(0)})

    对上述公式两侧求梯度,令其等于零,之后再进行整理,可得迭代公式(由于涉及矩阵求导数等一系列复杂操作,此处可以粗浅的理解一下):

X= X^{(0)} -H^{-1}f(X^{(0)}) \nabla f(X^{(0)})

    上述第一个公式中\nabla f(X^{(0)})表示在X^{(0)}点处的梯度值,\nabla^2f(X^{(0)})表示该点的二阶梯度也可以写成Hessian矩阵,迭代公式使用了Hessian矩阵的逆和梯度值来确定。

2.3. 多元函数牛顿法的python程序

from sympy import *
import numpy as np
# 假设多元函数是二维形式
# x_init为二维向量(x1, x2)
def newton_dou(step, x_init, obj):
    i = 1 # 记录迭代次数的变量
    while i <= step:
        if i == 1:
            grandient_obj = np.array([diff(obj, x1).subs(x1, x_init[0]).subs(x2, x_init[1]), diff(obj, x2).subs(x1, x_init[0]).subs(x2, x_init[1])], dtype=float) # 初始点的梯度值
            hessian_obj = np.array([[diff(obj, x1, 2), diff(diff(obj, x1), x2)], [diff(diff(obj, x2), x1), diff(obj, x2, 2)]], dtype=float) # 初始点的hessian矩阵
            inverse = np.linalg.inv(hessian_obj) # hessian矩阵求逆
            x_new = x_init - np.matmul(inverse, grandient_obj) # 第一次迭代公式
            print(x_new)
            # print('迭代第%d次:%.5f' %(i, x_new))
            i = i + 1
        else:
            grandient_obj = np.array([diff(obj, x1).subs(x1, x_new[0]).subs(x2, x_new[1]), diff(obj, x2).subs(x1, x_new[0]).subs(x2, x_new[1])], dtype=float) # 当前点的梯度值
            hessian_obj = np.array([[diff(obj, x1, 2), diff(diff(obj, x1), x2)], [diff(diff(obj, x2), x1), diff(obj, x2, 2)]], dtype=float) # 当前点的hessian矩阵
            inverse = np.linalg.inv(hessian_obj) # hessian矩阵求逆
            x_new = x_new - np.matmul(inverse, grandient_obj) # 迭代公式
            print(x_new)
            # print('迭代第%d次:%.5f' % (i, x_new))
            i = i + 1
    return x_new

x0 = np.array([0, 0], dtype=float)
x1 = symbols("x1")
x2 = symbols("x2")
newton_dou(5, x0, x1**2+2*x2**2-2*x1*x2-2*x2)

    程序执行的结果如下:

[1. 1.]
[1. 1.]
[1. 1.]
[1. 1.]
[1. 1.]

Process finished with exit code 0

    经过实际计算函数f(x)=x_1^2+2x_2^2-2x_1x_2-2x_2的极值点为(1,1),只需一次迭代就能收敛到极值点。

3. 结束语

    本文只是粗浅的将牛顿法的原理进行语言和程序描述,没有过多的探讨具体实施的细节,实际中机器学习等相关算法进行牛顿法迭代时并非如此编程。牛顿法由牛顿本人发现并命名,但是拉弗森早于牛顿发现的46年就已经提出该算法,现在牛顿法又称为牛顿-拉弗森方法。牛顿法有很多的缺点在此并没有讨论,例如在一元函数情况时,会产生导数为零不能迭代的情况或者迭代点有震荡往复等情况出现;多元函数的hessian矩阵计算困难,收敛过慢等情况,因此又产生了拟牛顿法和阻尼牛顿法等改进的方法,想进一步学习的读者可以参考非线性优化领域的相关书籍。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,233评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,013评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,030评论 0 241
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,827评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,221评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,542评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,814评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,513评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,225评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,497评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,998评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,342评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,986评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,055评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,812评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,560评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,461评论 2 266

推荐阅读更多精彩内容