题记:
这几天,一直在学习人工智能的进化算法,今天想通过一些简单的介绍,来介绍进化算法中的一种——
遗传算法(GA)
正文:
首先呢,我们来简答介绍一下什么是进化算法:
进化算法:
进化算法(evolutionary algorithms,EA)是基于自然选择和自然遗传等生物进化机制的一种搜索算法。生物进化是通过繁殖、变异、竞争和选择实现的;而进化算法则主要通过选择、重组和变异这三种操作实现优化问题的求解。进化算法是一个“算法簇”,包括遗传算法(GA)、遗传规划、进化策略和进化规划等,进化算法的基本框架是遗传算法所描述的框架。
既然我们已经了解到了进化算法的基本框架是遗传算法所描述的框架,那么我们就来简单的讲述一下遗传算法。
遗传算法:
首先我们来了解一下基本思想:
也就是说,在求解问题时从多个解开始,然后通过一定的法则进行逐步迭代以产生新的解。
我个人认为遗传算法就是一种概率型算法,通过不断的择优,选择出最接近最优解的的解(不一定就是最优解,但是可能无限接近)。
而他们到底是如何择优的呢?
举个小例子:
例如在一个种群内有5个人,他们分别叫:
- hello
- hoole
- hallo
- hooal
- oalha
我们可以把这5个人的名字看成5条染色体,这里他们的名字就可以看做为他们的染色体。
如果我们想培育出染色体为hello的人的话,我们是不是需要先选择出染色体最接近hello的人呢?(或者说名字最像hello的人)来组成下一代,当然了我们可以一眼看出第一项hello,他的染色体就是最接近hello的,但是,这个种群中还有存在交叉与变异的可能性。
只能暂且说,单在选择下,第一项的生存下来成为第二代种群的概率比较大,而其他人也可能发生交叉与变异,他们也有可能孕育出染色体为hello的人,只是概率比较小而已。但不代表他们不可能成为第二代种群。
那么下面有几个问题:
- 如何选择?
- 如何交叉?
- 如何变异?
1.对于选择,我们就引入了适应度的概念,适应度越高,就越有可能活下去成为下一代种群中的一份子,我们在选择个体中有很多方法:轮盘赌选择,锦标赛选择方法,Boltzmann锦标赛选择,最佳个体保存方法等。
我们选择比较简单的轮盘赌方法:
又称比例选择方法.其基本思想是:各个个体被选中的概率与其适应度大小成正比.
举个例子:
如果第一轮我们产生一个随机数为0.13,0.13<=0.14 我们选择第一个
第二轮我们产生一个随机数为0.65, 0.65<=0.69 则我们选择第三个
这就是轮盘赌的简单原理
2.对于交叉,存在很多:一点交叉、二点交叉、均匀交叉等
我们选择比较简单的一点交叉:
举个例子:
两个字符串
var str1 = hello;
var str2 = world;
假设他们两个相邻,字符串长度都为5,我随机选择选一个交叉点,我选择第0位进行交叉
两者交叉后,变为
horld
wello
即第一位以后的内容发送交换
3.对于变异,同样存在:位点变异,逆转变异,插入变异,交换变异等
我们选择的是位点变异,也就是说针对于某一位进行变异
举个例子:
10010
如果第2位发生变异,第2位为 0 变异为 1 ,结果如下:
10110
对于遗传算法的基础知识我们就介绍到这里。
那么问题就来了,也可以引出我们今天的主题:如何用JavaScript来实现这样的选择呢?
基于JavaScript的遗传算法的实现
我们来利用遗传算法解决一个实际问题:
二进制编码也就是指用二进制数来代替我们的染色体,这个染色体的范围在十进制数内是0-30
编码长度为5,也就是指5位
首先,我们要初始化一些变量:
var totalNum = 10, // 种群中染色体的总数
bit = 5, // 基因数为5位
total = new Array(); // 种群中的染色体
bestFitness = 0, // 最佳适应值
generation = 0, // 染色体代号
bestGeneration = 0, // 最好的一代染色体的代号
bestStr = ''; // 最好的染色体基因序列
接下来,我们就要初始化一条染色体,如何定义一条染色体呢?我们可以用一个二进制字符串来代表一条染色体,通过随机数,随机生成长度为5的字符串
/**
* 初始化一条染色体
*/
function initChar() {
var res = '';
for(var