首頁  >  文章  >  後端開發  >  Python實作遺傳演算法的程式碼

Python實作遺傳演算法的程式碼

黄舟
黄舟原創
2017-10-10 10:46:364580瀏覽

本篇主要介紹了Python 遺傳演算法,小編覺得還挺不錯的,現在分享給大家,也給大家做個參考。一起跟著小編過來看看吧

寫在前面

之前的文章中已經講過了遺傳演算法的基本流程,並且用MATLAB實作過一遍了。這篇文章主要面對的人群是看過了我之前的文章,因此我就不再贅述遺傳演算法是什麼以及基本的內容了,假設大家已經知道我是怎麼寫遺傳演算法的了。

Python的遺傳演算法主函數

我的想法是,創建一個染色體的類,其中包括了兩個變數:染色體chrom與適應度fitness。因此我們就可以透過直接建立物件來作為族群中的個體。


#染色体的类
class Chrom:
  chrom = []
  fitness = 0
  def showChrom(self):
    print(self.chrom)
  def showFitness(self):
    print(self.fitness)

所以我們開始設定基礎參數。其中族群的表達方式我用的是字典,也就是用一個字典來保存族群內的所有個體,這個也是我想出來的創造多個物件的方法。

將字典的索引為個體的標號,如:chrom1, chrom2等。字典索引的值就是一個物件。這個物件擁有兩個屬性,就是染色體與適應度。

其實在這方便來說,我覺得在思路上是優於利用MATLAB的矩陣式程式設計的。因為這樣可以很直觀的將個體與個體的屬性這一思想給表達出來,相比一堆矩陣來說,在邏輯上比較容易接受。


#基础参数
N = 200 #种群内个体数目
mut = 0.2 #突变概率
acr = 0.2 #交叉概率

pop = {} #存储染色体的字典
for i in range(N):
  pop['chrom'+str(i)] = Chrom()
chromNodes = 2 #染色体节点数(变量个数)
iterNum = 10000 #迭代次数
chromRange = [[0, 10], [0, 10]] #染色体范围
aveFitnessList = [] #平均适应度
bestFitnessList = [] #最优适应度

之後就是初始染色體了,其中就牽扯到了各種用來初始化種群、計算適應度、找到最優等函數,我在這裡分出了兩個文件,分別為Genetic.py與Fitness.py。

Genetic.py裡面有八個函數,主要包含了作用於族群或染色體運算的函數,分別為:

  1. findBest函數,用於尋找族群中的最優染色體;

  2. findworse函數,用於尋找族群中的最劣染色體;

  3. initialize函數,用於初始化族群;

  4. calAveFitness函數,用於計算族群的平均適應度;

  5. mutChrom函數,用於對染色體進行變異;

  6. inRange函數,用於判斷染色體節點值是否越界;

  7. #acrChrom函數,用於交叉染色體;

  8. ##compareChrom函數,用於比較兩個染色體孰優孰劣。

Fitness.py裡面有兩個函數,主要包含了適應度運算的函數,分別為:

  1. calFitness函數,用來迭代每一個個體,計算適應度(利用funcFitness函數計算);

  2. funcFitness函數,計算單一個體的適應度。

因此可以列出初始化程式碼為


#初始染色体
pop = Genetic.initialize(pop, chromNodes, chromRange)
pop = Fitness.calFitness(pop) #计算适应度
bestChrom = Genetic.findBest(pop) #寻找最优染色体
bestFitnessList.append(bestChrom[1]) #将当前最优适应度压入列表中
aveFitnessList.append(Genetic.calAveFitness(pop, N)) #计算并存储平均适应度

迭代過程的想法與邏輯與MATLAB無異


#开始迭代
for t in range(iterNum):
  #染色体突变
  pop = Genetic.mutChrom(pop, mut, chromNodes, bestChrom, chromRange)
  #染色体交换
  pop = Genetic.acrChrom(pop, acr, chromNodes)
  #寻找最优
  nowBestChrom = Genetic.findBest(pop)
  #比较前一个时间的最优和现在的最优
  bestChrom = Genetic.compareChrom(nowBestChrom, bestChrom)
  #寻找与替换最劣
  worseChrom = Genetic.findWorse(pop)
  pop[worseChrom[0]].chrom = pop[bestChrom[0]].chrom.copy()
  pop[worseChrom[0]].fitness = pop[bestChrom[0]].fitness
  #存储最优与平均
  bestFitnessList.append(bestChrom[1])
  aveFitnessList.append(Genetic.calAveFitness(pop, N))

最後再做一次迭代的圖片


#

plt.figure(1)
plt.plot(x, aveFitnessList)
plt.plot(x, bestFitnessList)
plt.show()

最後再在最前面加上各種函式庫和檔案就可以執行了。


import Genetic
import Fitness
import matplotlib.pyplot as plt
import numpy as np

感悟

#可以說最主要的感悟就是染色體這一類。其實那個Genetic.py與Fitness.py這兩個文件也可以直接包裝成類,但是這樣一來我就嫌主文件太臃腫,在其他裡面再包裝成類又多此一舉,畢竟這只是一個小程序,所以我就這樣寫了。

深刻感悟到了物件導向程式設計的優點,在程式邏輯的處理上真是一種享受,只需要思考物件的屬性即可,省去了許多複雜的思考。

另一個感想就是創建多個物件時,利用字典的方法來創建物件。當初我也是困惑怎麼建立一個類似C++中的物件數組,上網找了各種方法,結果都避而不談(當然,也可能是我搜尋能力太差沒找到),所以經過嘗試中遇到了這種方法。

等有空我再詳細說一下這個方法吧,這次就先到這裡。

剩餘的函數補充##首先是Genetic.py裡面的八個函數

import random

#寻找最优染色体
def findBest(pop):
  best = ['1', 0.0000001]
  for i in pop:
    if best[1] < pop[i].fitness:
      best = [i, pop[i].fitness]
  return best

#寻找最劣染色体
def findWorse(pop):
  worse = [&#39;1&#39;, 999999]
  for i in pop:
    if worse[1] > pop[i].fitness:
      worse = [i, pop[i].fitness]
  return worse

#赋初始值
def initialize(pop, chromNodes, chromRange):
  for i in pop:
    chromList = []
    for j in range(chromNodes):
      chromList.append(random.uniform(chromRange[j][0], chromRange[j][1]+1))
    pop[i].chrom = chromList.copy()
  return pop

#计算平均适应度
def calAveFitness(pop, N):
  sumFitness = 0
  for i in pop:
    sumFitness = sumFitness + pop[i].fitness
  aveFitness = sumFitness / N
  return aveFitness

#进行突变
def mutChrom(pop, mut, chromNodes, bestChrom, chromRange):
  for i in pop:
    #如果随机数小于变异概率(即可以变异)
    if mut > random.random():
      mutNode = random.randrange(0,chromNodes)
      mutRange = random.random() * (1-pop[i].fitness/bestChrom[1])**2
      pop[i].chrom[mutNode] = pop[i].chrom[mutNode] * (1+mutRange)
      #判断变异后的范围是否在要求范围内
      pop[i].chrom[mutNode] = inRange(pop[i].chrom[mutNode], chromRange[mutNode])
  return pop

#检验便宜范围是否在要求范围内
def inRange(mutNode, chromRange):
  if chromRange[0] < mutNode < chromRange[1]:
    return mutNode
  elif mutNode-chromRange[0] > mutNode-chromRange[1]:
    return chromRange[1]
  else:
    return chromRange[0]

#进行交叉
def acrChrom(pop, acr, chromNodes):
  for i in pop:
    for j in pop:
      if acr > random.random():
        acrNode = random.randrange(0, chromNodes)
        #两个染色体节点进行交换
        pop[i].chrom[acrNode], pop[j].chrom[acrNode] = pop[j].chrom[acrNode], pop[i].chrom[acrNode]
  return pop

#进行比较
def compareChrom(nowbestChrom, bestChrom):
  if bestChrom[1] > nowbestChrom[1]:
    return bestChrom
  else:
    return nowbestChrom

然後是Fitness.py的兩個函數

import math

def calFitness(pop):
  
  for i in pop:
    #计算每个染色体的适应度
    pop[i].fitness = funcFitness(pop[i].chrom)

  return pop

def funcFitness(chrom):
  #适应度函数
  fitness = math.sin(chrom[0])+math.cos(chrom[1])+0.1*(chrom[0]+chrom[1])

以上是Python實作遺傳演算法的程式碼的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn