tft每日頭條

 > 科技

 > python牛頓法求解最小值

python牛頓法求解最小值

科技 更新时间:2024-08-17 23:20:46
7.4 函數求導

函數y= f(x)的導數表示因變量y關于自變量x的變化率,記為f(x)或dy/dx。我們可以通過創建Derivative類的對象來對函數進行求導。以之前的汽車行駛例子中的函數為例:


>>> from sympy import Symbol, Derivative # ① >>> t = Symbol('t') >>> St = 5*t**2 2*t 8 >>> Derivative(St, t) Derivative(5*t**2 2*t 8, t)


我們在①處導入Derivative類,在②處創建一個Derivative類的對象,創建對象時傳遞的兩個參數分别是函數S(t)(符号St)和變量t(符号t)。和Limit類一樣,首先返回一個Derivative類的對象,此時并沒有真正計算導數。我們調用doit()函數對未計算的Derivative類的對象求導:


>>> d = Derivative(St, t) >>> d.doit() 10*t 2


導數的表達式為10*t 2。現在,我們希望計算一個特定值t處的導數值,比如說或t=1,可以使用subs()函數:


>>> d.doit().subs({t:t_1}) 10*t_1 2 >>> d.doit().subs({t:1}) 12 >>>


下面試着考慮一個僅以x為變量的複雜的函數


>>> from sympy import Derivative, Symbol >>> x = Symbol('x') >>> y = (x**3 x**2 x)* (x**2 x) >>> Derivative(y, x) Derivative((x**2 x)*(x**3 x**2 x), x) >>> Derivative(y, x).doit() (2*x 1)*(x**3 x**2 x) (x**2 x)*(3*x**2 2*x 1)


可以看到這個函數是兩個獨立的函數的乘積形式,這意味着,我們需要使用微分鍊式法則來計算這個導數。但不用擔心,隻需創建Derivative類的對象來處理就可以了。

你還可以嘗試其他的複雜表達式,比如說涉及三角函數的表達式。

7.4.1 求導計算器

現在我們來編寫一個求導計算器程序,它将以以一個函數作為輸入,然後輸出關于指定變量的導數:


''' Derivative calculator ''' from sympy import Symbol, Derivative, sympify, pprint from sympy.core.sympify import SympifyError def derivative(f, var): var = Symbol('var') d = Derivative(f, var).doit() pprint(d) if __name__ == '__main__': f = input('Enter a function: ') # ① var = input('Enter the variable to differentiate with respect to : ') try: f = sympify(f) # ② except SympifyError: print('Invalid input') else: derivative(f, var) # ③


在①處,我我們提示用戶輸入一個要求導的函數,然後詢問用戶要這個函數的哪個變量求導。在②處,我們使用sympify()函數将輸入函數轉換為SymPy對象,我們在try...except模塊中調用sympify()函數,從而可以在用戶無效輸入的情況下顯示錯誤信息。如果輸入函數有效,我們在③處調用求導函數derivative(),此時将轉換後的輸入函數以及要求導的變量作為輸入參數。

在derivative()函數中,首先創建一個對應于求 導變量的Symbol對象,并使用标簽var來指代這個變量。接下來,創建一個Derivative 對象,并将輸入函數f和Symbol對象var 作為輸入參數。調用doit()函數計算導數,然後使用pprint()函數輸出結果,使其看起來接近于它相應的數學公式。程序的運行示例如下:


Enter a function: 2*x**2 3*x 1 Enter the variable to differentiate with respect to : x 4⋅x 3


以下是一個二元函數的運行實例:


Enter a function: x**2 y**2 Enter the variable to differentiate with respect to : x 2⋅x


7.4.2 求偏導數

在上一個程序裡,我們看到可以使用Derivative類對多變量函數中的其中任意一個變量求導,這種計算通常被稱為計算偏導數,“偏”意味着我們假設僅有一個變量變化,而其他變量固定。

考慮函數。f(x,y)關于x的偏導數是。先前的程序可以用來計算偏導數,隻需要指定正确的變量即可:


Enter a function: 2*x*y x*y**2 Enter the variable to differentiate with respect to : x 2 y 2⋅y



注:這一章要做的一個關鍵假設就是,我們要計算導數的所有函數在它們的定義域中都是可導的。


7.5 高階導數和最大最小值點

默認情況下,使用Derivative類創建一個導數對象是求一階導數。為求高階導數,隻需在創建Derivative對象時将求導階數作為第三個參數即可。這一節裡我們将演示如何使用函數的一階和二階導數在區間上找到最大和最小值點。

考慮函數,定義域為[-5,5],注意我使用了方括号表示定義域是閉區間,即自變量可以是-5到5之間的任何數,包括端點。

python牛頓法求解最小值(Python數學編程第七章)1

x^5-30x^3 50x的函數圖像

由圖中可以看到函數在區間[-2, 0]上在點B取到最小值。類似地,在區間[0,2]上在點C取到最大值。另一方面,在x的整個定義域上,函數分别在A點和D點處取得最大和最小值。因此,當考慮整個區間[-5, 5]上的函數時,點B和點C分别稱為局部最小值和局部最大值,而點A和點D分别稱為全局最大值和全局最小值。 極值點是指函數取局部或全局最大或最小值的點。如果x是函數f(x)的極值點,那麼f(x)在x點處的一階導數(記為f'(x))必須為0。這個性質表明尋找可能的極值點的一個好方法就是求解方程f(x)=0, 該方程的解稱為函數的極值點。 試着做一 下:


>>> from sympy import Symbol, solve, Derivative >>> x = Symbol('x') >>> f = x**5 - 30*x**3 50*x >>> d1 = Derivative(f, x).doit()


現在我們計算了一階導數f'(x),接下來解f'(x)=0以得到極值點:


>>> crtical_points = solve(d1) >>> crtical_points [-sqrt(9 - sqrt(71)), sqrt(9 - sqrt(71)), -sqrt(sqrt(71) 9), sqrt(sqrt(71) 9)]


這裡顯示的crtical_points列表中的數字分别對應于圖中的B、C、A和D。我們将創建這标簽來分别指代這些點,然後在命令行中使用這些标簽:


>>> A = crtical_points[2] >>> B = crtical_points[0] >>> C = crtical_points[1] >>> D = crtical_points[3]


因為這個函數的所有極值點都在所考慮的區間内,它們都和我們要搜尋的f(x)的全局最大和最小值相關。現在應用所謂的二階導數檢驗來縮小可能的全局最大和最小值點的範圍。

首先,我們計算函數f(x)的二階導數。注意,為計算二階導數,我們輸入2作為第三個參數:


>>> d2 = Derivative(f, x, 2).doit()


現在我們通過将每一個極值點逐一代入x來求該點處的二階導數值。如果結果小于0,則該值為局部最大值;如果結果大于0,則該值為局部最小值;如果結果等于0,則不能得出結論,即不能判斷極值點x是否為局部最大值、最小值或二者都不是。


>>> d2.subs({x:B}).evalf() 127.661060789073 >>> d2.subs({x:C}).evalf() -127.661060789073 >>> d2.subs({x:A}).evalf() -703.493179468151 >>> d2.subs({x:D}).evalf() 703.493179468151


對極值點的二階導數檢驗進行計算,結果可知A和C是局部最大值點,B和D是局部最小值點。 區間[-5,5]上f(x)的全局最大值和最小值是在極值點x處或者在定義域的某一端點(x=-5和x=5)處獲得的。我們已經找到了所有極值點,即點A、B、C和D。函數不可能在點A或C達到全局最小值,因為它們是局部最大值點。同理,函數不可能在點B或D達到全局最大值。 因此,為找到全局最大值,我們必須計算f(x)在點A、C、-5和5處的值。在這些點中,f(x)取最大值的地方一定是全局最大值。我們将創建兩個标簽,x_ min 和x max,來分别指代定義域邊界,然後在點A、C、x_ min和x max處分别計算函數值:


>>> x_min = -5 >>> x_max = 5 >>> f.subs({x:A}).evalf() 705.959460380365 >>> f.subs({x:C}).evalf() 25.0846626340294 >>> f.subs({x:x_min}).evalf() 375.000000000000 >>> f.subs({x:x_max}).evalf() -375.000000000000


通過上述計算,以及所有極值點這定義域邊界處函數值的比較,我們發現A點為是全局最大值點。

類似地,為了确定全局最小值點,我們需要在計算函數在B、D點和端點處的函數值。


>>> f.subs({x:B}).evalf() -25.0846626340294 >>> f.subs({x:D}).evalf() -705.959460380365 >>> f.subs({x:x_min}).evalf() 375.000000000000 >>> f.subs({x:x_max}).evalf() -375.000000000000


f(x)值最小的點一定是函數的全局最小值點,比較後可知結果是D點。

隻要函數二階可導,上述求函數極值的方法始終有效,即通過考慮所有極值點(通過二階導數檢驗去除一些極值點後)和邊界點處的函數值。二階可導意味着函數在定義域内的一階導數和二階導數都存在。 類似形式的函數在定義域中可能不存在極值點,但這種情形下該方法仍然有效,它告訴我們:極值點在定義域邊界上。

,

更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!

查看全部

相关科技资讯推荐

热门科技资讯推荐

网友关注

Copyright 2023-2024 - www.tftnews.com All Rights Reserved