python實現——最優化算法(二分法、格點法、黃金分割法、牛頓法等)

二分法

函數詳見rres,此代碼使該算法運行了兩次

def asdf(x):
    rres=8*x**3-2*x**2-7*x+3
    return rres

i=2
left=0
right=1
while i>0 :
    i = i-1
    ans = 0.1
    mid1 = (left + right + ans) / 2
    mid2 = (left + right - ans) / 2
    a=asdf(mid1)
    c=asdf(mid2)
    if a > c :
        right = mid1
    else :
        left = mid2
b=(left+right) / 2
print("左極限=%s,右極限=%s,極小值x=%s"%(left,right,b))
左極限=0.45,右極限=0.775,極小值x=0.6125

收獲:
這是我第一個實現的代碼。學習完該算法以后,邏輯框架基本上就有了,剩下需要明確的就是對應的python的語言。于是我就開始了查找“如何定義函數”(詳見mofan的優酷),“循環體”和“if條件語句”的格式(https://blog.csdn.net/qq_39407518/article/details/79822498)“數學符號”(詳見mofan的優酷),以及print的使用

1.def是python中指定義,一般用來定義函數,如果需要深度學習搭建網絡可用來定義網絡。值得注意的一點是

return必須要加在函數后面另起一行。

我不清楚為什么,但是如果沒有加的話,那個函數公式就是一個花瓶,就像一個結果輸不出去。

2.最坑的就是邏輯。一開始邏輯沒理清楚,或者說在代碼上有疏漏,導致我將left和right放在了循環體里,結果可想而知。不過也是因為這個錯誤,我知道pycharm中的debug怎么用,挺簡單的,百度一下就出來了。

3.不知道什么原因,看的莫煩視頻中的print多個變量一起輸出是沒有辦法在我的pycharm中使用的,出來的結果很奇怪。可能是因為我是win10不是ios吧。print如果多個變量一起輸出必須是print("名字:%s,名字2:%s"%(a,b))結果輸出就是名字:a ,名字2:b

問題:1.為什么要加return?

return的意思是輸出這個def里面任意一個變量值作為結果顯示。一般情況而言,是輸出函數的關系式的命名,這樣當你調用這個函數的時候,變量對應的函數值才能顯示出來,否則只運行沒有結果,不會有效果。

格點法——三點等分法

import numpy as np
def qwer(x):
    third = np.exp(x) - 5*x
    return third

left = 1
right = 2
mid1 =float(left+right) / 2
mid2 = (left+mid1) / 2
mid3 = (mid1+right) /2
a = qwer(mid1)
b = qwer(mid2)
c = qwer(mid3)
i = 5
while i > 0:
    i=i-1
    if a > b:
        if c > b :
            #b
            right = mid1
            mid1 = mid2
            a=b
            mid2 = (left + mid1) / 2
            mid3 = (mid1 + right) / 2
            b = qwer(mid2)
            c = qwer(mid3)
        else:#b>c
            #c
            left = mid1
            mid1 = mid3
            a = c
            mid2 = (left + mid1) / 2
            mid3 = (mid1 + right) / 2
            b = qwer(mid2)
            c = qwer(mid3)
    else:#b>a
            if a > c:
                #C
                left = mid1
                mid1 = mid3
                a = c
                mid2 = (left + mid1) / 2
                mid3 = (mid1 + right) / 2
                b = qwer(mid2)
                c = qwer(mid3)
            else:#b>a&c>a
                # a
                left = mid2
                right = mid3
                mid2 = (left + mid1) / 2
                mid3 = (mid1 + right) / 2
                b = qwer(mid2)
                c = qwer(mid3)

print("最小值=%s"%mid1)
print("函數值=%s"%a)
最小值=1.609375
函數值=-3.047189552275773

關于python中數據變量。第一遍運行結果出現很明顯不對,于是我采用了debug。結果發現,mid1處一直為1而不是1.5,于是就開始了解數據變量。起初我猜測python默認所有變量為整型,但是根據二分法的結果我意識到此猜測不對,所以要改整個file的變量格式沒有必要。所以我就在mid1式子前面加了一個float,結果就顯示為1.5了。但是如果我將整個式子用()括起來,前面加float,結果還是1。我不太理解為什么。不過我知道了python的數據格式是根據輸入量決定的,也就是說你的輸入量如果是整型,那么與其直接相關的計算輸出結果一定是整型,而且還是不采用進位的整型。在我沒有采用+float/+.0這兩種方法之前,mid1~3全部是整型。

left = 1.0
right = 2.0
mid1 =(left+right) / 2

或者不再mid1前面加float,直接將輸入量后面點個點就行
真的很想吐槽一下print,好麻煩啊啊啊啊每次都得弄個%s,而且有時候還不能放一起!!!!

Fibonacci法

def fibonacci(n):
    i=0
    a = 0
    b = 1
    for i in range(n):
        i=i+1
        c = a+b
        a = b
        b = c
    return c
def bn(x):
    ert = x**2 - 6*x + 2
    return ert
z = 2
p = 0
left = 0.00000
right = 10.00000
L1 = right - left
while z < 100:
    m = fibonacci(z)
    l = L1/m
    k = 1.000/m
    if k < 0.03:
        print("n=%s,Fn=%s"%(z,m))
        L2 = l*fibonacci(z-1)
        t = left + L2
        r = right -L2
        while p < 3:
            p = p + 1
            l3 = t - r
            e= bn(t)
            o = bn(r)
            if e>o :
                right = t
                t = r
                r = left + l3
            else:#o>e
                left = r
                r = t
                t = right - l3
        break
    else:
        z = z + 1

okk=(left+right)/2
okky=bn(okk)
print(left)
print(right)
print("極小值x=",okk)
print("極小值y=",okky)

不要問我掌握了什么,要問我現在寫完這個代碼后有多么的愛python的精度表示 :-)我決定以后只要再編寫數學公式的代碼都將輸入量的小數學點后面補很多0
fibonacci函數定義,每次debug后我的手都是抖的O(∩_∩)O~

黃金分割法

def gold(x):
    gg= x**2 - 6*x + 9
    return gg

left = 1
right = 7
ans = 0.4
a = left + 0.618 * (right - left)
b = left + 0.382*(right - left)
gga = gold(a)
ggb = gold(b)
i = 0
while i < 7:
    print("i=%s" % i)
    print("left=%s,right=%s" % (left, right))
    print("x左=%s,x右=%s" % (a, b))
    print("y左=%s,y右=%s" % (ggb, gga))
    c = right - left
    if c > 0.4:
        i = i + 1
        if gga > ggb:
            right = a
            a = b
            b = left + 0.382*(right - left)
            gga = ggb
            ggb = gold(b)
        else:#gga<ggb
            left = b
            b = a
            a = left + 0.618 * (right - left)
            ggb = gga
            gga = gold(a)
    else:
        break

不知道自己什么時候有的強迫癥,只要是代碼下面有“~”我就必須要消掉。笑哭。這個很簡單,前四個除了費波納茨,都很簡單。

間接法——二次插值法

def yy(x):
    y=x**4-4*x**3-6*x**2-16*x+4
    return y

def xing(xm1,xm2,xm3,fm1,fm2,fm3):
    yxxx=0.5000*((xm2**2-xm3**2)*fm1+(xm3**2-xm1**2)*fm2+(xm1**2-xm2**2)*fm3)/((xm2-xm3)*fm1+(xm3-xm1)*fm2+(xm1-xm2)*fm3)
    return yxxx

x1 = -1.0000
f1 = yy(x1)
x3 = 6
f3 = yy(x3)
x2 = 0.50000*(x1+x3)
f2 = yy(x2)
xp = xing(x1,x2,x3,f1,f2,f3)
fp = yy(xp)
a = abs(xp-x2)
while abs(xp-x2) > 0.05000:
    a = abs(xp - x2)
    if xp > x2:
        if fp > f2:
            x3=xp
            f3=fp
            xp = xing(x1, x2, x3, f1, f2, f3)
            fp = yy(xp)
            print("ans=%s" % a)
            print("left=%s,right=%s" % (x1, x3))
            print("x*=%s,fp*=%s" % (xp, fp))
            print("x2=%s,f2=%s" % (x2, f2))
            print("******************")
        else:#f2>fp
            x1 = x2
            f1 = f2
            x2 = xp
            f2 = fp
            xp = xing(x1, x2, x3, f1, f2, f3)
            fp = yy(xp)
            print("ans=%s" % a)
            print("left=%s,right=%s" % (x1, x3))
            print("x*=%s,fp*=%s" % (xp, fp))
            print("x2=%s,f2=%s" % (x2, f2))
            print("******************")
    else:#xp<x2
        if fp > f2:
            x1 = xp
            f1 = fp
            xp = xing(x1, x2, x3, f1, f2, f3)
            fp = yy(xp)
            print("ans=%s" % a)
            print("left=%s,right=%s" % (x1, x3))
            print("x*=%s,fp*=%s" % (xp, fp))
            print("x2=%s,f2=%s" % (x2, f2))
            print("******************")
        else:
            x3 = x2
            f3 = f2
            x2 = xp
            f2 = fp
            xp = xing(x1, x2, x3, f1, f2, f3)
            fp = yy(xp)
            print("ans=%s" % a)
            print("left=%s,right=%s" % (x1, x3))
            print("x*=%s,fp*=%s" % (xp, fp))
            print("x2=%s,f2=%s" % (x2, f2))
            print("******************")

這個公式看起來很麻煩,便寫的時候更要謹慎。我上回把那個2擱在了分號下面,結果很大,所以還是換算成0.5更好(PS:勿忘那長河般的0)。
雖然代碼很長,但是主要是因為print太多。本打算在開頭print,最后結果會漏掉最后一部分。懶得想其他辦法了,直接就這樣吧

間接法——牛頓法

def fd(x):
    y = 4*x**3-12*x**2-12*x-16
    return y
def fdd(x):
    ys = 12*x**2-24*x-12
    return ys

i = 1
x0 = 3.00000
ans = 0.001
while i < 7:
    fd0 = fd(x0)
    fdd0 = fdd(x0)
    if abs(fd0) > ans:
        x1 = x0 - (fd0/fdd0)
        x0 = x1
        print("次數:%s,所得的值x:%s"%(i,x1))
        i = i + 1
    else:#fd0<0.001
        print("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$")
        print("Bingo!順利通關!祝您開學愉快!")
        print("Boss  X=%s"%x0)
        break

一開始while里面<寫成了>,導致run不出來。繼而,debug也沒法用。在網上一查才知道 “沒聯網”+“沒選斷點”。最后想嘗試將else里面的內容輸出來,結果發現run以后被刷屏了。于是改成i<7以后還是不行,于是想著加一個break跳出循環,結果成效了。
然后剛剛由debug了一下,才知道原來是i+1在if里面,因為沒有辦法+1,所以i=6一直存在,就不斷循環。因為加break也好,i+1也好,都可以。

就在一個半小時前,我成功搞完了最優化六大代碼,純手打,無外力。開心!

這是我第一組自己實現的python代碼,就是數學公式用python語言組裝起來。剛開始的時候知道大概需要在語言中體現什么,但不太清楚。于是我就在網上找了幾個二分法的,他們都各有不同,但框架都差不多,不過如果要用到我們的那個公式里還需要改變很多。然后我就開始分析我們的題,我發現大體需要兩部分,一部分函數定義,一部分循環體。但我不知道如何定義函數,如何寫數學公式,如何弄變量,也就是說一些小點不太會,所以我選擇直接百度。因為我知道自己閱讀的能力不錯,相比于從視頻中提取要素,我更擅長通過閱讀獲得要點。有目的性地找知識點,掌握地更牢固。
于是我就開始了第一個——二分法的編寫。我發現,自己出現了很多錯誤而且有很多地方都很基礎。但我依然沒選擇視頻,而是將這些問題直接在百度上找,因為視頻講完或許你也沒找到點。當然,這是一步一步走的,不是直接就將程序擺上去,一點一點改。
隨著前兩個的成功,我發現自己對于這些代碼有了自信,似乎看透了他們的偽裝,抓住了本質。除此之外,我還意識到自己自從8月份以后,學習能力似乎提高了不少,而且有了更為有效的學習方法。各方面都有了一定的覺醒。除了第一個找了幾個牛頭不對馬嘴的代碼,其他都是根據自己的邏輯寫,邏輯通下來以后,對應語言中某一部分不知道如何翻譯就去百度,其實這幾個套路都一樣或者說數學公式轉化的套路都一樣。
我還意識到,匯編其實是最難的語言,目前為止所學到的,因為很多都需要自己去定義,去死摳,需要記住大量的指令且不能靈活變通。但是其他的卻只需要將一些對應的記下來就好。python真的挺簡單的。而且,我發現自己今天似乎打開了新世界的大門,我愛上了這種充滿了靈性的東西,充滿了嚴謹的美麗,還有那未知的變化,我發現我似乎愛上了代碼。可能不僅僅局限于python,這些語言都充滿了挑戰性。我覺得當你疑惑的時候,就需要相信直覺,至少我發現它很準

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,156評論 6 529
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 97,866評論 3 413
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 174,880評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,398評論 1 308
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,202評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,743評論 1 320
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,822評論 3 438
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 41,962評論 0 285
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,476評論 1 331
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,444評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,579評論 1 365
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,129評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,840評論 3 344
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,231評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,487評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,177評論 3 388
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,568評論 2 370