最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

使用Python實(shí)現(xiàn)遺傳算法的完整代碼

 更新時(shí)間:2023年03月23日 15:48:31   作者:琪琪%¥%  
這篇文章主要介紹了使用Python實(shí)現(xiàn)遺傳算法,其本質(zhì)是一種高效、并行、全局搜索的方法,自適應(yīng)的控制搜索過程以求得最優(yōu)解,需要的朋友可以參考下

遺傳算法是模仿自然界生物進(jìn)化機(jī)制發(fā)展起來的隨機(jī)全局搜索和優(yōu)化方法,它借鑒了達(dá)爾文的進(jìn)化論和孟德爾的遺傳學(xué)說。其本質(zhì)是一種高效、并行、全局搜索的方法,它能在搜索過程中自動獲取和積累有關(guān)搜索空間的知識,并自適應(yīng)的控制搜索過程以求得最優(yōu)解。遺傳算法操作使用適者生存的原則,在潛在的解決方案種群中逐次產(chǎn)生一個(gè)近似最優(yōu)解的方案,在遺傳算法的每一代中,根據(jù)個(gè)體在問題域中的適應(yīng)度值和從自然遺傳學(xué)中借鑒來的再造方法進(jìn)行個(gè)體選擇,產(chǎn)生一個(gè)新的近似解。這個(gè)過程導(dǎo)致種群中個(gè)體的進(jìn)化,得到的新個(gè)體比原來個(gè)體更能適應(yīng)環(huán)境,就像自然界中的改造一樣。

遺傳算法具體步驟:

(1)初始化:設(shè)置進(jìn)化代數(shù)計(jì)數(shù)器 t=0、設(shè)置最大進(jìn)化代數(shù) T、交叉概率、變異概率、隨機(jī)生成 M 個(gè)個(gè)體作為初始種群 P

(2)個(gè)體評價(jià):計(jì)算種群 P 中各個(gè)個(gè)體的適應(yīng)度

(3)選擇運(yùn)算:將選擇算子作用于群體。以個(gè)體適應(yīng)度為基礎(chǔ),選擇最優(yōu)個(gè)體直接遺傳到下一代或通過配對交叉產(chǎn)生新的個(gè)體再遺傳到下一代

(4)交叉運(yùn)算:在交叉概率的控制下,對群體中的個(gè)體兩兩進(jìn)行交叉

(5)變異運(yùn)算:在變異概率的控制下,對群體中的個(gè)體進(jìn)行變異,即對某一個(gè)體的基因進(jìn)行隨機(jī)調(diào)整

(6) 經(jīng)過選擇、交叉、變異運(yùn)算之后得到下一代群體 P1。

重復(fù)以上(1)-(6),直到遺傳代數(shù)為 T,以進(jìn)化過程中所得到的具有最優(yōu)適應(yīng)度個(gè)體作為最優(yōu)解輸出,終止計(jì)算。

旅行推銷員問題(Travelling Salesman Problem, TSP):有 n 個(gè)城市,一個(gè)推銷員要從其中某一個(gè)城市出發(fā),唯一走遍所有的城市,再回到他出發(fā)的城市,求最短的路線。

應(yīng)用遺傳算法求解 TSP 問題時(shí)需要進(jìn)行一些約定,基因是一組城市序列,適應(yīng)度是按照這個(gè)基因的城市順序的距離和分之一。

1.2 實(shí)驗(yàn)代碼

import random
import math
import matplotlib.pyplot as plt
# 讀取數(shù)據(jù)
f=open("test.txt")
data=f.readlines()
# 將cities初始化為字典,防止下面被當(dāng)成列表
cities={}
for line in data:
    #原始數(shù)據(jù)以\n換行,將其替換掉
    line=line.replace("\n","")
    #最后一行以EOF為標(biāo)志,如果讀到就證明讀完了,退出循環(huán)
    if(line=="EOF"):
        break
    #空格分割城市編號和城市的坐標(biāo)
    city=line.split(" ")
    map(int,city)
    #將城市數(shù)據(jù)添加到cities中
    cities[eval(city[0])]=[eval(city[1]),eval(city[2])]
 
# 計(jì)算適應(yīng)度,也就是距離分之一,這里用偽歐氏距離
def calcfit(gene):
    sum=0
    #最后要回到初始城市所以從-1,也就是最后一個(gè)城市繞一圈到最后一個(gè)城市
    for i in range(-1,len(gene)-1):
        nowcity=gene[i]
        nextcity=gene[i+1]
        nowloc=cities[nowcity]
        nextloc=cities[nextcity]
        sum+=math.sqrt(((nowloc[0]-nextloc[0])**2+(nowloc[1]-nextloc[1])**2)/10)
 
    return 1/sum
 
# 每個(gè)個(gè)體的類,方便根據(jù)基因計(jì)算適應(yīng)度
class Person:
    def __init__(self,gene):
        self.gene=gene
        self.fit=calcfit(gene)
class Group:
    def __init__(self):
        self.GroupSize=100  #種群規(guī)模
        self.GeneSize=48    #基因數(shù)量,也就是城市數(shù)量
        self.initGroup()
        self.upDate()
    #初始化種群,隨機(jī)生成若干個(gè)體
    def initGroup(self):
        self.group=[]
        i=0
        while(i<self.GroupSize):
            i+=1
            #gene如果在for以外生成只會shuffle一次
            gene=[i+1 for i in range(self.GeneSize)]
            random.shuffle(gene)
            tmpPerson=Person(gene)
            self.group.append(tmpPerson)
 
    #獲取種群中適應(yīng)度最高的個(gè)體
    def getBest(self):
        bestFit=self.group[0].fit
        best=self.group[0]
        for person in self.group:
            if(person.fit>bestFit):
                bestFit=person.fit
                best=person
        return best
    #計(jì)算種群中所有個(gè)體的平均距離
    def getAvg(self):
        sum=0
        for p in self.group:
            sum+=1/p.fit
        return sum/len(self.group)
    #根據(jù)適應(yīng)度,使用輪盤賭返回一個(gè)個(gè)體,用于遺傳交叉
    def getOne(self):
        #section的簡稱,區(qū)間
        sec=[0]
        sumsec=0
        for person in self.group:
            sumsec+=person.fit
            sec.append(sumsec)
        p=random.random()*sumsec
        for i in range(len(sec)):
            if(p>sec[i] and p<sec[i+1]):
                #這里注意區(qū)間是比個(gè)體多一個(gè)0的
                return self.group[i]
    #更新種群相關(guān)信息
    def upDate(self):
        self.best=self.getBest()
# 遺傳算法的類,定義了遺傳、交叉、變異等操作
class GA:
    def __init__(self):
        self.group=Group()
        self.pCross=0.35    #交叉率
        self.pChange=0.1    #變異率
        self.Gen=1  #代數(shù)
 
    #變異操作
    def change(self,gene):
        #把列表隨機(jī)的一段取出然后再隨機(jī)插入某個(gè)位置
        #length是取出基因的長度,postake是取出的位置,posins是插入的位置
        geneLenght=len(gene)
        index1 = random.randint(0, geneLenght - 1)
        index2 = random.randint(0, geneLenght - 1)
        newGene = gene[:]       # 產(chǎn)生一個(gè)新的基因序列,以免變異的時(shí)候影響父種群
        newGene[index1], newGene[index2] = newGene[index2], newGene[index1]
        return newGene
 
    #交叉操作
    def cross(self,p1,p2):
        geneLenght=len(p1.gene)
        index1 = random.randint(0, geneLenght - 1)
        index2 = random.randint(index1, geneLenght - 1)
        tempGene = p2.gene[index1:index2]   # 交叉的基因片段
        newGene = []
        p1len = 0
        for g in p1.gene:
              if p1len == index1:
                    newGene.extend(tempGene)     # 插入基因片段
                    p1len += 1
              if g not in tempGene:
                    newGene.append(g)
                    p1len += 1
        return newGene
 
    #獲取下一代
    def nextGen(self):
        self.Gen+=1
        #nextGen代表下一代的所有基因
        nextGen=[]
        #將最優(yōu)秀的基因直接傳遞給下一代
        nextGen.append(self.group.getBest().gene[:])
        while(len(nextGen)<self.group.GroupSize):
            pChange=random.random()
            pCross=random.random()
            p1=self.group.getOne()
            if(pCross<self.pCross):
                p2=self.group.getOne()
                newGene=self.cross(p1,p2)
            else:
                newGene=p1.gene[:]
            if(pChange<self.pChange):
                newGene=self.change(newGene)
            nextGen.append(newGene)
        self.group.group=[]
        for gene in nextGen:
            self.group.group.append(Person(gene))
            self.group.upDate()
 
    #打印當(dāng)前種群的最優(yōu)個(gè)體信息
    def showBest(self):
        print("第{}代\t當(dāng)前最優(yōu){}\t當(dāng)前平均{}\t".format(self.Gen,1/self.group.getBest().fit,self.group.getAvg()))
 
    #n代表代數(shù),遺傳算法的入口
    def run(self,n):
        Gen=[]  #代數(shù)
        dist=[] #每一代的最優(yōu)距離
        avgDist=[]  #每一代的平均距離
        #上面三個(gè)列表是為了畫圖
        i=1
        while(i<n):
            self.nextGen()
            self.showBest()
            i+=1
            Gen.append(i)
            dist.append(1/self.group.getBest().fit)
            avgDist.append(self.group.getAvg())
        #繪制進(jìn)化曲線
        plt.plot(Gen,dist,'-r')
        plt.plot(Gen,avgDist,'-b')
        plt.show()
 
ga=GA()
ga.run(3000)
print("進(jìn)行3000代后最優(yōu)解:",1/ga.group.getBest().fit)

1.3 實(shí)驗(yàn)結(jié)果

下圖是進(jìn)行一次實(shí)驗(yàn)的結(jié)果截圖,求出的最優(yōu)解是 11271

為避免實(shí)驗(yàn)的偶然性,進(jìn)行 10 次重復(fù)實(shí)驗(yàn),并求平均值,結(jié)果如下。

上圖橫坐標(biāo)是代數(shù),縱坐標(biāo)是距離,紅色曲線是每一代的最優(yōu)個(gè)體的距離,藍(lán)色曲線是每一代的平均距離??梢钥闯鰞蓷l線都呈下降趨勢,也就是說都在進(jìn)化。平均距離下降說明由于優(yōu)良基因的出現(xiàn)(也就是某一段城市序列),使得這種優(yōu)良的性狀很快傳播到整個(gè)群體。就像自然界中的優(yōu)勝劣汰一樣,具有適應(yīng)環(huán)境的基因才能生存下來,相應(yīng)的,生存下來的都是具有優(yōu)良基因的。算法中引入交叉率和變異率的意義就在于既要保證當(dāng)前優(yōu)良基因,又要試圖產(chǎn)生更優(yōu)良的基因。如果所有個(gè)體都交叉,那么有些優(yōu)良的基因片段可能會丟失;如果都不交叉,那么兩個(gè)優(yōu)秀的基因片段無法組合為更優(yōu)秀的基因;如果沒有變異,那就無法產(chǎn)生更適應(yīng)環(huán)境的個(gè)體。不得不感嘆自然的智慧是如此強(qiáng)大。

上面說到的基因片段就是 TSP 中的一小段城市序列,當(dāng)某一段序列的距離和相對較小時(shí),就說明這段序列是這幾個(gè)城市的相對較好的遍歷順序。遺傳算法通過將這些優(yōu)秀的片段組合起來實(shí)現(xiàn)了 TSP 解的不斷優(yōu)化。而組合的方法正是借鑒自然的智慧,遺傳、變異、適者生存。

1.4 實(shí)驗(yàn)總結(jié)

1、如何在算法中實(shí)現(xiàn)“優(yōu)勝劣汰”?

所謂優(yōu)勝劣汰也就是優(yōu)良的基因保留,不適應(yīng)環(huán)境的基因淘汰。在上述 GA 算法中,我使用的是輪盤賭,也就是在遺傳的步驟中(無論是否交叉),根據(jù)每個(gè)個(gè)體的適應(yīng)度來挑選。這樣就能達(dá)到適應(yīng)度高得個(gè)體有更多的后代,也就達(dá)到了優(yōu)勝劣汰的目的。

在具體的實(shí)現(xiàn)過程中,我犯了個(gè)錯(cuò)誤,起初在遺傳步驟篩選個(gè)體時(shí),我每選出一個(gè)個(gè)體就將這個(gè)個(gè)體從群體中刪除。現(xiàn)在想想,這種做法十分愚蠢,盡管當(dāng)時(shí)我已經(jīng)實(shí)現(xiàn)了輪盤賭,但如果選出個(gè)體就刪除,那么就會導(dǎo)致每個(gè)個(gè)體都會平等地生育后代,所謂的輪盤賭也不過是能讓適應(yīng)度高的先進(jìn)行遺傳。這種做法完全背離了“優(yōu)勝劣汰”的初衷。正確的做法是選完個(gè)體進(jìn)行遺傳后再重新放回群體,這樣才能保證適應(yīng)度高的個(gè)體會進(jìn)行多次遺傳,產(chǎn)生更多后代,將優(yōu)良的基因更廣泛的播撒,同時(shí)不適應(yīng)的個(gè)體會產(chǎn)生少量后代或者直接被淘汰。

2 、如何保證進(jìn)化一直是在正向進(jìn)行?

所謂正向進(jìn)行也就是下一代的最優(yōu)個(gè)體一定比上一代更適應(yīng)或者同等適應(yīng)環(huán)境。我采用的方法是最優(yōu)個(gè)體直接進(jìn)入下一代,不參與交叉變異等操作。這樣能夠防止因這些操作而“污染”了當(dāng)前最優(yōu)秀的基因而導(dǎo)致反向進(jìn)化的出現(xiàn)。

我在實(shí)現(xiàn)過程中還出現(xiàn)了另一點(diǎn)問題,是傳引用還是傳值所導(dǎo)致的。對個(gè)體的基因進(jìn)行交叉和變異時(shí)用的是一個(gè)列表,Python 中傳列表時(shí)傳的實(shí)際上是一個(gè)引用,這樣就導(dǎo)致個(gè)體進(jìn)行交叉和變異后會改變個(gè)體本身的基因。導(dǎo)致的結(jié)果就是進(jìn)化非常緩慢,并且伴隨反向進(jìn)化。

3、交叉如何實(shí)現(xiàn)?

選定一個(gè)個(gè)體的片段放入另一個(gè)體,并將不重復(fù)的基因的依次放入其他位置。

在實(shí)現(xiàn)這一步時(shí),因?yàn)閷W(xué)生物時(shí)對真實(shí)染色體行為的固有認(rèn)識,“同源染色體交叉互換同源區(qū)段”,導(dǎo)致我錯(cuò)誤實(shí)現(xiàn)該功能。我只將兩個(gè)個(gè)體的相同位置的片段互換來完成交叉,顯然這樣的做法是錯(cuò)誤的,這會導(dǎo)致城市的重復(fù)出現(xiàn)。

4、在剛開始寫這個(gè)算法時(shí),我是半 OOP,半面向過程地寫。

后續(xù)測試過程中發(fā)現(xiàn)要改參數(shù),更新個(gè)體信息時(shí)很麻煩,于是全部改為 OOP,然后方便多了。對于這種模擬真實(shí)世界的問題,OOP 有很大的靈活性和簡便性。

5、如何防止出現(xiàn)局部最優(yōu)解?

在測試過程中發(fā)現(xiàn)偶爾會出現(xiàn)局部最優(yōu)解,在很長時(shí)間內(nèi)不會繼續(xù)進(jìn)化,而此時(shí)的解又離最優(yōu)解較遠(yuǎn)。哪怕是后續(xù)調(diào)整后,盡管離最優(yōu)解近了,但依然是“局部最優(yōu)”,因?yàn)檫€沒有達(dá)到最優(yōu)。

算法在起初會收斂得很快,而越往后就會越來越慢,甚至根本不動。因?yàn)榈胶笃?,所有個(gè)體都有著相對來說差不多的優(yōu)秀基因,這時(shí)的交叉對于進(jìn)化的作用就很弱了,進(jìn)化的主要動力就成了變異,而變異就是一種暴力算法了。運(yùn)氣好的話能很快變異出更好的個(gè)體,運(yùn)氣不好就得一直等。

防止局部最優(yōu)解的解決方法是增大種群規(guī)模,這樣就會有更多的個(gè)體變異,就會有更大可能性產(chǎn)生進(jìn)化的個(gè)體。而增大種群規(guī)模的弊端是每一代的計(jì)算時(shí)間會變長,也就是說這兩者是相互抑制的。巨大的種群規(guī)模雖然最終能避免局部最優(yōu)解,但是每一代的時(shí)間很長,需要很長時(shí)間才能求出最優(yōu)解;而較小的種群規(guī)模雖然每一代計(jì)算時(shí)間快,但在若干代后就會陷入局部最優(yōu)。

猜想一種可能的優(yōu)化方法,在進(jìn)化初期用較小的種群規(guī)模,以此來加快進(jìn)化速度,當(dāng)適應(yīng)度達(dá)到某一閾值后,增加種群規(guī)模和變異率來避免局部最優(yōu)解的出現(xiàn)。用這種動態(tài)調(diào)整的方法來權(quán)衡每一代計(jì)算效率和整體計(jì)算效率之間的平衡。

到此這篇關(guān)于使用Python實(shí)現(xiàn)遺傳算法的完整代碼的文章就介紹到這了,更多相關(guān)Python實(shí)現(xiàn)遺傳算法內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • pandas計(jì)算最大連續(xù)間隔的方法

    pandas計(jì)算最大連續(xù)間隔的方法

    今天小編就為大家分享一篇pandas計(jì)算最大連續(xù)間隔的方法,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-07-07
  • python如何在文件中部插入信息

    python如何在文件中部插入信息

    這篇文章主要介紹了python如何在文件中部插入信息問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • Python的Flask框架與數(shù)據(jù)庫連接的教程

    Python的Flask框架與數(shù)據(jù)庫連接的教程

    這篇文章主要介紹了Python的Flask框架與數(shù)據(jù)庫連接的教程,是Flask框架學(xué)習(xí)當(dāng)中的基本知識,需要的朋友可以參考下
    2015-04-04
  • python3光學(xué)字符識別模塊tesserocr與pytesseract的使用詳解

    python3光學(xué)字符識別模塊tesserocr與pytesseract的使用詳解

    這篇文章主要介紹了python3光學(xué)字符識別模塊tesserocr與pytesseract的使用詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-02-02
  • Python 模擬購物車的實(shí)例講解

    Python 模擬購物車的實(shí)例講解

    下面小編就為大家?guī)硪黄狿ython 模擬購物車的實(shí)例講解。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-09-09
  • 基于python爬蟲數(shù)據(jù)處理(詳解)

    基于python爬蟲數(shù)據(jù)處理(詳解)

    下面小編就為大家?guī)硪黄趐ython爬蟲數(shù)據(jù)處理(詳解)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-06-06
  • Python實(shí)現(xiàn)RSA加密解密

    Python實(shí)現(xiàn)RSA加密解密

    這篇文章主要介紹了Python實(shí)現(xiàn)RSA加密解密,加密技術(shù)在數(shù)據(jù)安全存儲,數(shù)據(jù)傳輸中發(fā)揮著重要作用,能夠保護(hù)用戶隱私數(shù)據(jù)安全,防止信息竊取。RSA是一種非對稱加密技術(shù),在軟件、網(wǎng)頁中已得到廣泛應(yīng)用,下面文章更多相關(guān)內(nèi)容需要的小伙伴可以參考一下
    2022-04-04
  • python實(shí)現(xiàn)遠(yuǎn)程控制電腦

    python實(shí)現(xiàn)遠(yuǎn)程控制電腦

    這篇文章主要為大家詳細(xì)介紹了python實(shí)現(xiàn)遠(yuǎn)程控制電腦,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-05-05
  • Python實(shí)現(xiàn)一個(gè)優(yōu)先級隊(duì)列的方法

    Python實(shí)現(xiàn)一個(gè)優(yōu)先級隊(duì)列的方法

    這篇文章主要介紹了Python實(shí)現(xiàn)一個(gè)優(yōu)先級隊(duì)列的方法,文中講解非常細(xì)致,代碼幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下
    2020-07-07
  • Python基礎(chǔ)知識點(diǎn) 初識Python.md

    Python基礎(chǔ)知識點(diǎn) 初識Python.md

    在本篇文章中我們給大家總結(jié)了關(guān)于Python基礎(chǔ)知識點(diǎn),通過初識Python.md的相關(guān)內(nèi)容分享給Python初學(xué)者,一起來看下吧。
    2019-05-05

最新評論

宿州市| 进贤县| 三明市| 许昌县| 齐齐哈尔市| 中卫市| 宝鸡市| 涟水县| 隆安县| 朔州市| 祁阳县| 郑州市| 曲麻莱县| 蒙城县| 大方县| 汾阳市| 南雄市| 定襄县| 商水县| 汾西县| 盖州市| 灵璧县| 天台县| 永顺县| 金平| 商城县| 木里| 金坛市| 芜湖市| 留坝县| 额敏县| 藁城市| 昭苏县| 望谟县| 那坡县| 湖南省| 肃南| 通海县| 江永县| 福清市| 汾阳市|