python实现遗传算法,gif动图展示结果
[id_[id_[id_6[id_6[id_150[id_1449[id_13428434[id_212573098]]3[id_833[id_1215668373]665]9]86193]032[id_5618780[id_178[id_1906[id_1462873792]544]41152]]6][id_[id_1722[id_7282322[id_6173[id_5425[id_[id_18[id_1010821624]55444]5509081]563]142]]0[id_[id_[id_1431135224]4804557][id_[id_1771098668]04[id_2[id_[id_727695099]4840781]013[id_1590135033]][id_3078[id_1095149050]958]2]92[id_4013722[id_277313330]]6]3][id_1225356863]82976]7[id_18320[id_20[id_1489682032][id_1904270759]8214][id_50[id_1115684627]20490]8]0][id_[id_[id_12[id_271765872]797585]2989140][id_1[id_301769805][id_8009[id_37110[id_1524390591]90]742]2[id_[id_10590087[id_1650898420]]13[id_1050142710]9836]16]71[id_18665847[id_778325[id_203276161]]][id_140420[id_681299421]77]]8[id_8[id_108746296]9[id_855[id_[id_172[id_874248124]0447]308[id_81[id_20689486[id_216157712]]7900][id_3380188[id_1132157450]]]24533]58250]02594]4[id_507670626]768585]
这里先放最后的结果:
[id_1[id_1553655503]4139313]
[id_[id_1603964483]29723557][id_[id_643154217]0162397]
[id_153424499]
选定解码方法时,我选择了二进制编码,因为它既直观又便捷,设定精确度达到0.0001,函数变量x的取值区间为,据此计算得出需要17位二进制数,解码程序代码如下:
[id_199167453] def decode(genCode): y 等于零,加上 genCode 的二进制表示转换成的整数,除以二进制的十六万七千六百五十一减一,再乘以九 [id_[id_1312697676]1475921] 1 2 3 4
遗传算法的表现很大程度上取决于初始群体的构成,若选取不当,便极易被困于局部最优解kaiyun全站app登录入口kaiyun全站登录网页入口,因此必须重视种群的开创阶段,合理设定初始值,以提升整体优化能力,避免搜索过程过早停滞,确保算法能够探索到更广阔的解空间,获得更理想的最终结果。
设置初始种群规模为十,包含十个由十七位字符构成的字符串 population = [] #总群 for i in range(20): strCode = '' for j in range(17): strCode加上了随机生成的零或一,用数字表示 population.append(strCode) 1 2 3 4 5 6 7
[id_93376[id_1117963388]03]
评价函数接收种群和初始化函数作为参数,根据这些输入计算适应度值,用于后续的进化过程,评估每个个体的优劣程度,为选择和繁殖提供依据 value = [] 对于群体中的每一个个体,依次进行遍历, 列表value中添加了通过initFunction函数处理后的结果,该结果由decode函数对种群中第i个个体进行解码后得到 if value[i] < 0: value[i] = 0 return value 1 2 3 4 5 6 7 8
轮盘赌方法用于挑选,模拟竞争中的胜者,依据每个体的生存能力,决定哪些个体能够被选中,进行下一轮的繁衍
挑选子代群体,依据适应度结果 childPopulation = [] Sumfitness = [] [id_1273003998] 在健身结果列表中,每个元素逐一进行遍历,依次处理 if i == 0: Sumfitness加入fitnessResult中的第i个值 else: Sumfitness的当前值等于前一个值加上fitnessResult的对应值,然后把这个结果存入Sumfitness中 对于Sumfitness的每一个索引值, indiviSumP加入了一个值,这个值是Sumfitness中第j个元素除以fitnessResult所有元素的总和,用逗号隔开 对于种群中的每一个个体编号,依次进行遍历 x = np.random.uniform(0,1) if x <= indiviSumP[0]: childPopulation列表加入首个元素,该元素来自population列表 else: 对于种群中的每一个个体,从第二个开始遍历,依次进行操作, 如果倒数第二个个体和为小于等于x,并且x小于等于倒数第一个个体和 childPopulation列表加入人口数组中对应的值 break return childPopulation 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
进行优胜个体间的信息交换,以模拟繁殖产生新一代,这种交换过程以概率为调控手段,反映了自然界中颜色体交换的普遍现象,因此设定固定的交换概率为0.7,而变异现象则较为少见开元棋官方正版下载,其概率值设定为0.002
#对选择后的子代进行一定概率的染色提交换 新群体与父代进行交叉操作,交叉概率为pc crossChildPopulation = [] #如果为单身则先选择出单shen 当新种群数量为奇数时, 随机选择一个索引值,这个索引值介于零和当前种群长度的数值之间,randmSingleNum用来存储这个随机生成的索引值 新增种群中的某个个体被加入到子种群中,这个个体是通过随机选取原始种群中的一个成员来确定的,选取过程使用了一个随机生成的数字作为索引 删除新种群中随机选取的一个个体 中值等于新种群长度除以二的结果取整 新种群的前半部分赋值给父亲,长度为总体数量的一半 子代数组后半部分赋值给母亲变量 np.random.shuffle(father) np.random.shuffle(mother) for i in range(half): 长宽比是介于零和一之间的随机数,通过等概率分布函数生成,数值存储在变量crossP中 if pc >= crossP: breakPoint是使用随机数生成的,取值范围从零到新种群中个体基因长度的最大值之间,通过整数型随机函数确定具体数值 子 = 父亲[i]的前面部分拼接上母亲[i]的后面部分 子项等于母项从零到断点的部分,再加上父项从断点开始的部分 else: [id_1187746787] daughter = mother[i] 新增子代对象至集合中 将女儿加入到子代群体列表中 return crossChildPopulation 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
6-变异获得子代
#变异 变异情况依据子代种群与交叉概率计算得出 variationPopulation = [] 对于每一代杂交子代群体中的个体,依次遍历其索引号码 variationP是一个介于零和一之间的随机浮点数 variationPos是随机取的整数,范围从零到交叉子种群中第一个个体的长度之间 if variationP <= pc: if variationPos == 0: 当数组中第i个元素的第一个字符为数字0时 crossChildPopulation第i个元素赋值为字符'1'加上crossChildPopulation第i个元素从第二个字符开始到末尾的所有字符 else: crossChildPopulation第i个元素赋值为0加上crossChildPopulation第i个元素从第二个字符到末尾的子字符串 else: 当交叉子代种群中第i个位置的变异值为0时 交叉子代种群数组第i个元素的前面部分与后面部分拼接,中间插入数字1,形成新的子代种群数组第i个元素 else: crossChildPopulation数组第i个元素的前variationPos-1个字符不变,第variationPos个字符替换为0,后面的字符保持不变 新个体加入变异种群列表中,该个体来自交叉子代种群的第i个位置 return variationPopulation 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
然后进行多步训练即可:
[id_1145408792] 适应度值等于适应度函数计算种群和初始函数的结果 挑选出子代群体,依据适应度值进行选择 新后代 = 交叉父代(挑选子代,0.7) 种群 = 变异(交叉子代,0.02) 1 2 3 4 5 6
但是我们想要模拟动态过程,所以我们需要引入
在matplotlib的动画模块中,有一个名为FuncAnimation的函数 导入matplotlib中的animation模块 1 2
这个可以用来制作我们的动态效果,参照前面内容。大家可以去官方资料里查询这个的具体操作方法,或者直接留言,我会把得到动态效果图片的代码贴出来。
def updata(i): global population x1是一个列表,其中的每个元素都初始化为0,列表的长度与population的长度相同 y1用零填充,长度与种群规模相同,每个位置初始化为零,用列表推导式生成 设置画布尺寸为十五乘以十,确保保存图像时界面不发生压缩 文件路径 = 文件夹路径 + 文件名 + 图片格式, 文件夹路径 = 'C:\Users\Amie\Desktop\png\', 文件名 = '{0}', 图片格式 = '.png', 使用格式化方法将它们组合在一起 图像保存至指定路径,分辨率设定为六百,边缘颜色设置为红色 fitnessValue = fitnessfunction(population,initFunction) selectChildes = selectChild(population,fitnessValue) crossChild = crossParent(selectChildes,0.7) population = variation(crossChild,0.02) 对于群体中的每一个个体,依次遍历, x1[i] = decode(population[i]) y1第i个值等于初始化函数处理解码后的种群第i个个体结果 [id_[id_1644561435]5392614] sca1.set_offsets(data) [id_1451209393] return sca1 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
我们现在只需整合所有功能模块,便能够实现动态呈现模拟遗传算法的图像展示,具体实现代码如下:
从未来导入除法运算 import math import numpy as np 导入matplotlib.pyplot模块,命名为plt from matplotlib.animation import FuncAnimation from matplotlib import animation 画布尺寸设定为十五乘以十,宽高比分别为十五和十,用于绘制图形 ax1 = fig.add_subplot(111) ax1.set_xlim([0,10]) ax1.set_ylim([-10,15]) #定义函数 def initFunction(x): y 等于 x 加上 5 乘以正弦函数乘以 5 乘以 x, 再加上 2 乘以余弦函数乘以 3 乘以 x return y #形成一些点用于绘图(这里生成900个点) x等于零点零一乘以i的所有结果,i的取值范围是一到八百九十九,每个值都除以一百 y等于零到八百九十九的每个数字除以八百九十九的余数 for i in range(900): y[i] = initFunction(x[i]) ax1.plot(x,y) #初始化种群数(假设初始种群数目为10个),10个17位位str population = [] for i in range(20): strCode = '' for j in range(17): strCode += str(np.random.randint(0,2)) population.append(strCode) #解码 def decode(genCode): y = 0 + int(genCode,2)/(2**17-1)*9 return y m通过遍历population的长度来生成一个等长的序列 列表 n 包含从零到种群规模减一的每个整数,每个整数对应种群中的一个个体 for i in range(len(population)): 数组元素n中的第i个值,等于初始化函数处理后得到的结果,该结果由解码函数处理了从种群数组中弹出的第i个元素,而种群数组是通过弹出操作获取的 m[i] = decode(population[i]) sca1 = ax1的点图(m,n)进行标记,以便后续进行修改 # #适应度函数,其中负数置零的步骤可以调整 def fitnessfunction(population,initFunction): value = [] for i in range(len(population)): value.append(initFunction(decode(population[i]))) if value[i] < 0: value[i] = 0 return value #采用轮盘赌算法进行选择 #输入是种群的适应度函数值向量 父辈群体经过筛选,产生后代群体,该后代群体称为childPopulation def selectChild(population,fitnessResult): childPopulation = [] Sumfitness = [] indiviSumP = [] for i in range(len(fitnessResult)): if i == 0: Sumfitness.append(fitnessResult[i]) else: Sumfitness.append(Sumfitness[i-1] + fitnessResult[i]) for j in range(len(Sumfitness)): indiviSumP.append(Sumfitness[j]/sum(fitnessResult)) for childNum in range(len(population)): x = np.random.uniform(0,1) if x <= indiviSumP[0]: childPopulation.append(population[0]) else: for m in range(1,len(population)): if indiviSumP[m-1] <= x and x <= indiviSumP[m]: childPopulation.append(population[m]) break return childPopulation #对选择后的子代进行一定概率的染色提交换 def crossParent(new_population,pc): crossChildPopulation = [] #如果为单身则先选择出单shen if len(new_population)%2 != 0: randmSingleNum = np.random.randint(0,len(new_population)) crossChildPopulation.append(new_population[randmSingleNum]) del(new_population[randmSingleNum]) half = int(len(new_population)/2) father = new_population[:half] mother = new_population[half:] np.random.shuffle(father) np.random.shuffle(mother) for i in range(half): crossP = np.random.uniform(0,1) if pc >= crossP: breakPoint = np.random.randint(0,len(new_population[0])) son = father[i][:breakPoint] + mother[i][breakPoint:] daughter = mother[i][:breakPoint] + father[i][breakPoint:] else: son = father[i] daughter = mother[i] crossChildPopulation.append(son) crossChildPopulation.append(daughter) return crossChildPopulation #变异 def variation(crossChildPopulation,pc): variationPopulation = [] for i in range(len(crossChildPopulation)): variationP = np.random.uniform(0,1) variationPos = np.random.randint(0,len(crossChildPopulation[0])) if variationP <= pc: if variationPos == 0: if crossChildPopulation[i][0] == '0': crossChildPopulation[i] = '1'+crossChildPopulation[i][1:] else: crossChildPopulation[i] = '0'+crossChildPopulation[i][1:] else: if crossChildPopulation[i][variationPos] == '0': crossChildPopulation[i] = crossChildPopulation[i][:variationPos-1] + '1' + crossChildPopulation[i][variationPos:] else: crossChildPopulation[i] = crossChildPopulation[i][:variationPos-1] + '0' + crossChildPopulation[i][variationPos:] variationPopulation.append(crossChildPopulation[i]) return variationPopulation def updata(i): global population x1 = [0 for j in range(len(population))] y1 = [0 for j in range(len(population))] 设置画布尺寸为十五乘以十,确保保存图像时界面不发生压缩 fitnessValue = fitnessfunction(population,initFunction) selectChildes = selectChild(population,fitnessValue) crossChild = crossParent(selectChildes,0.7) population = variation(crossChild,0.02) for i in range(len(population)): x1[i] = decode(population[i]) y1[i] = initFunction(decode(population[i])) data = [[x,y] for x,y in zip(x1,y1)] sca1.set_offsets(data) print(list(zip(x1,y1))) return sca1 ani是动画模块的动态画图函数,其参数fig指定图形,func指定更新函数,frames设定动画帧数范围,init_func设定初始函数,interval设置间隔时间,blit设定是否使用双缓冲 plt.show() 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
源代码链接:
网址是百度网盘分享的地址,文件编号为1WL14a5-Q3tsqoIuJSikx4A,访问时需要输入解锁码,密码是ggu0。