遗传算法是一种智能优化算法,通常用于求解复杂的数学问题。相比于传统方法,遗传算法摒弃了盲目的穷举或完全随机的求解策略,借鉴了自然界优胜劣汰、自然进化的思想,快速逼近最优解。上文对遗传算法的基本内容进行了介绍,本文将通过一个例子的讲解带领读者深入遗传算法的每一个具体步骤,并用python完整地实现整个算法,题目如下图所示。
第一步:编码
通过对题目的分析,这是一个包含两个自变量的复杂函数,而且规定了自变量的取值范围。为保证精度,我们将保留小数点后四位小数。下面考虑如何将两个自变量编码成二进制:1.为了满足精度的同时避免使用小数点,我们需要将自变量乘以10000;2.为了节省内存,我们应该根据自变量的取值范围确定2进制的位数。
上图很清楚地展示了编码的思路和过程,首先根据自变量的取值范围确定二进制的位数(分别对应18位和15位),然后将两个01串拼接成一个长度为33的01串。这个二进制串可以看作一条染色体,0或1可以看作基因,接下来的交叉、变异操作都将在这个二进制串上进行。
第二步:种群初始化
种群中应包含一定数目的染色体(33位的二进制),这些染色体使用随机数的方法完成初始化。用python实现这一功能非常简单,双重for循环+随机数函数轻松解决,代码很容易理解,这里不再啰嗦。
第三步:计算个体适应度
有了初始化的种群,下面让我们开启“上帝视角”,判断种群中每个个体对自然的适应程度。由于我们的目的是寻找函数的最大值,因此题目中的函数就是我们“自然法则”,我们要将33位的二进制数解析成两个自变量,然后带入函数计算结果,结果越大代表适应度越强,在进化过程中更容易得到上帝的垂青。在下图的python代码中,将二进制转换成十进制之后,要将自变量转换到指定取值范围。
第四步:开始进化
选择。“物竞天择,适者生存”是进化论的核心思想,接下来要根据个体的适应度来决定哪些个体被淘汰,哪些个体继续进化。为了避免陷入局部最优解,维护自然界的公平正义,我们采用轮盘赌的方法。所有个体都可能被淘汰,只不过适应度越低,被淘汰的概率越高。下图的python代码不长,相信读者一看就懂。
交叉。经过自然法则的选择之后幸存下来的个体开始繁衍生息,生命的繁衍过程实际上是染色体相互交叉的过程,目的是生成适应度更高的后代。我们设定一个参数“交叉率”,利用“上帝之手”--随机数对是否进化做出选择。产生0~32之间的随机整数对两个33位的二进制数进行切割,并交叉重组。
变异。自然界中的基因突变,也可以完全用程序实现。变异的概率很低,我们需要设定另外一个参数“变异率”,通过修改染色体上随机位置的一个基因实现变异。下图中的python代码中replace_char( )函数为自定义函数,功能是实现了指定位置字符的替换,参见完整代码。
多代进化
以上的步骤构成了种群的一次完整进化过程,当然为了得到最优解,我们需要让种群进行成百上千代的进化。再多的世代对python而言都是一个for循环的事。第一次实验,我设置的参数:进化世代为1000,种群规模为100,交叉率0.7,变异率0.1,结果显示在335代时得到最优解,x1=11.6284,x2=5.3241,此时函数的最大值为38.4342,各世代最优解如下所示。
总结
本文从一个例子出发,详细讲解了遗传算法的具体步骤和python实现,应该说整体的思路还是很清晰的,如果使用numpy代码会更简洁,当然还有更简单的实现方法,matlab和python的sklearn包中都集成了遗传算法工具包,只需要几行代码就能完成遗传算法的计算,但是我觉得自己动手实现有助于加深我们对遗传算法的理解。完整代码已上传,老规矩,如果需要请在下方评论留言。
|