Python实现遗传算法:基于面向对象与字典管理的完整代码解析
本文详细介绍使用Python实现遗传算法的核心代码结构。通过定义Chromosome类封装染色体与适应度,并利用字典管理种群个体,实现了直观的对象化编程。文章解析了Genetic与Fitness模块中的关键函数,包括初始化、交叉、变异及最优解查找逻辑,并提供了完整的迭代优化与可视化示例,帮助开发者快速掌握遗传算法的工程实现。
前言
在前面的文章中,我们已经梳理了遗传算法的基本流程,并使用MATLAB进行了实现。本文的目标读者是已经阅读过前述内容、了解遗传算法基本概念的人群,因此不再重复解释算法原理,而是直接聚焦于Python环境下的具体实现细节。
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文件中包含八个主要函数,负责种群操作或染色体层面的处理,具体包括:
- findBest函数:用于在种群中查找适应度最高的最优染色体;
- findWorse函数:用于在种群中查找适应度最低的最劣染色体;
- initialize函数:用于对种群进行初始化操作;
- calAveFitness函数:用于计算整个种群的平均适应度;
- mutChrom函数:用于对染色体执行变异操作;
- inRange函数:用于判断染色体节点的值是否超出预设范围;
- acrChrom函数:用于对染色体执行交叉操作;
- compareChrom函数:用于比较两个染色体的优劣。
Fitness.py文件中包含两个主要函数,专注于适应度的计算,具体包括:
- calFitness函数:用于遍历种群中的每个个体,并调用funcFitness函数计算其适应度;
- 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中的函数也可以包装成类,但这会导致主文件过于臃肿,且在外部再次封装显得多余。鉴于这是一个小型程序,当前的写法更为简洁。
深刻体会到面向对象编程的优势。在逻辑处理上,只需关注对象的属性,省去了许多底层细节的复杂思考,编程体验更加顺畅。
另一个感悟是关于创建多个对象的方法。起初我困惑于如何在Python中实现类似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 = ['1', 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])
以上就是本文的全部内容,希望对各位的学习有所帮助,也欢迎大家继续支持本站。
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













