我在实现我心爱的“遗传算法”。很明显,每次经过选择、交叉和变异的迭代后,种群数量会大幅增加。但是,生物体也会死亡,对吗?然而,我们所知的算法中并没有这样的规定。
所以我的问题是,为什么我们不直接从种群中淘汰一些适应性较低的生物体(同时也融入适者生存的理论)呢?为什么要承担它们的负担并浪费资源(在我们的例子中是内存)呢?
另外,我所有的思考都是基于Peter Norvig的AI书中对算法的三页解释,所以我的问题可能已经有人研究过了。我需要了解这些情况。
这是我在这个平台上的第一个问题,所以社区,请对我不要太苛刻!
回答:
遗传算法通过设计上的方式来淘汰集合中最弱的解,只需在未来的世代中不包含它们的基因即可。
遗传算法如何选择谁生谁死
摘要:想象一下,算法正在选择哪些解将被选择、组合和变异以进入下一代。每个解都被放在一个飞镖靶上,但更好的解会在飞镖靶上占据更多的空间,因此当算法投掷飞镖时,更有可能击中更适应的解。实际上,它甚至可能多次击中同一个解。
一旦从飞镖靶上获得了解集(通常与原始集合的种群大小相同,但可能包含由于多次飞镖击中同一解而产生的重复项),你就拿这个集合,并通过随机交换解的部分来“变异”它们。然后你可以“交配”解,这是一个非常性感的过程,你从新一代中随机选择解的部分,并将它们结合起来形成最终的世代集合。
然后重复这个过程。
没有被飞镖击中的解会怎么样?这完全取决于你的语言和数据结构,但它们可能是会被垃圾回收的对象。
实际代码
这是我在处理(Java)中编写的一些模拟飞镖投掷过程的代码
我只是将生物体称为浮点数的ArrayList,但它们可以是任何东西
ArrayList<Float> normalize(ArrayList<Float> inputArray){ float sum = 0; ArrayList<Float> outputArray = new ArrayList<Float>(); for(int i = 0; i < inputArray.size(); i++){ sum += inputArray.get(i); } for(int i = 0; i < inputArray.size(); i++){ outputArray.add(inputArray.get(i)/sum); } return outputArray; }ArrayList<Float> pick(ArrayList<ArrayList> parents, ArrayList<Float> fitness){ float searchVal = random(0, 1); float fitTotal = 0; int fitIndex = 0; while(searchVal > fitTotal && fitIndex < fitness.size()){ fitTotal += fitness.get(fitIndex); fitIndex++; } if(fitIndex != 0){ return parents.get(fitIndex-1); } else{ return parents.get(0); } }
工作原理
这段代码包含两个方法;一个是normalize方法,一个是pick方法。
normalize方法获取每个解的适应度水平,并将其“标准化”成一个数组,其中每个适应度水平除以总和。这将导致每个适应度水平成为总和的一个百分比。它们将全部加起来等于一。
pick方法随后会接收这个标准化数组,以及父解数组(必须与适应度水平的顺序相同),并选择一个0-1之间的随机数,这个数字将匹配到一个特定的适应度水平,算法将“选择”该父解进行繁殖。
你会注意到,适应度水平较高的解将有更高的被“选择”的机会。
这个“pick”方法应该针对你希望在下一代中的每个生物体重复执行。
编辑
原帖提到他们理解了飞镖靶的比喻,并想知道是否有用将不好的解完全从飞镖靶上抹去。选择坏后代的几率本来就很低,但像这样手动修剪也是可行的。
我认为这在有你不希望解具有的非常糟糕的特征的情况下会很有用,你不希望它们有任何机会进入下一组。