用Python实现简单的遗传算法
2010-02-15 14:00
这几天一直在用Python写一个简单的遗传算法,好自己拿来实验。断断续续的折腾了几天,今天下午终于写了一个简单的出来。整个代码还是仿照《游戏编程中的人工智能技术》中的代码来写的。如果想简单的学习一下遗传算法以及简单应用《游戏编程中的人工智能技术》是不错的选择。电子版及源代码可以参照找个网址:
http://download.csdn.net/source/337118
代码如下( 点击这里下载): # -*- coding:utf-8 -*- # file: GA.py # by: bluebanboom 0(0 # mail: bluebanboom@gmail.com ~ # date: 2008-10-22 # note: import random class genome: def __init__(self, length = 0): self.fitness = 0 self.bits = [] for i in range(length): self.bits.append(random.randint(0, 1)) class ga: """ simple Genetic Algorithms by bluebanboom reference: AI Techniques for Game Programming """ def __init__(self, pop_size, genome_len, expr = 'y = 0 - 2 * x * x + 8 * x + 4', crossover_rate = 0.7, mutation_rate = 0.01, max_generation = 1000 ): self.crossover_rate = crossover_rate self.mutation_rate = mutation_rate self.pop_size = pop_size self.genome_len = genome_len self.generation = 0 self.genomes = [] self.busy = False self.fittest_genome = genome() self.best_fitness_score = 0 self.total_fitness_score = 0 self.expr = expr self.max_generation = max_generation def create_start_populations(self): del self.genomes[0:] for i in range(self.pop_size): self.genomes.append(genome(self.genome_len)) self.generation = 0 self.best_fitness_score = 0 self.total_fitness_score = 0 def selection(self): f_slice = random.uniform(0, 1) * self.total_fitness_score c_f_slice = 0.0 selected_genome = 0 for i in range(self.pop_size): c_f_slice = c_f_slice + self.genomes[i].fitness if c_f_slice > f_slice: selected_genome = i break return self.genomes[i] def crossover(self, mum, dad): baby1 = [] baby2 = [] if (random.uniform(0, 1) > self.crossover_rate): baby1 = mum.bits; baby2 = dad.bits; return baby1, baby2 cp = random.randint(0, self.genome_len - 1) for i in range(cp): baby1.append(mum.bits[i]) baby2.append(dad.bits[i]) for i in range(cp, self.genome_len): baby1.append(dad.bits[i]) baby2.append(mum.bits[i]) return baby1, baby2 def mutate(self, bits): if (random.uniform(0, 1) < self.mutation_rate): mp = random.randint(0, self.genome_len - 1) bits[mp] = int(not bits[mp]) def decode(self, gen): x = self.bin2int(gen) exec(self.expr) return y def bin2int(self, lists): m = 1 r = 0 lists.reverse() for i in range(len(lists)): r = r + m * lists[i] m = m * 2 lists.reverse() return r def update_fitness_scores(self): self.total_fitness_score = 0 for i in range(self.pop_size): self.genomes[i].fitness = self.decode(self.genomes[i].bits) self.total_fitness_score += self.genomes[i].fitness if self.genomes[i].fitness > self.best_fitness_score: self.best_fitness_score = self.genomes[i].fitness self.fittest_genome = self.genomes[i] def epoch(self): self.update_fitness_scores() new_babies = 0 baby_genomes = [] baby1 = genome() baby2 = genome() while (new_babies < self.pop_size): mum = self.selection() dad = self.selection() baby1.bits, baby2.bits = self.crossover(mum, dad) self.mutate(baby1.bits) self.mutate(baby2.bits) baby_genomes.append(baby1) baby_genomes.append(baby2) new_babies = new_babies + 2 self.genomes = baby_genomes self.generation += 1 if self.generation >= self.max_generation: self.busy = False def start(self): self.busy = True self.create_start_populations() def get_best_genome(self): return self.fittest_genome.bits def get_best_variable(self): return self.bin2int(self.fittest_genome.bits) def get_max_value(self): return self.decode(self.fittest_genome.bits) def main(): print "-----------------" testga = ga(pop_size = 8, genome_len = 4, expr = 'y = 0 - 2 * x * x + 12 * x + 5') testga.start() while testga.busy: testga.epoch() print "Function: %s" % testga.expr print "The best genome is: ", print testga.get_best_genome() print "The variable is: %d" % testga.get_best_variable() print "The max value is %d" % testga.get_max_value() del testga print "-----------------" testga = ga(pop_size = 8, genome_len = 4) testga.start() while testga.busy: testga.epoch() print "Function: %s" % testga.expr print "The best genome is: ", print testga.get_best_genome() print "The variable is: %d" % testga.get_best_variable() print "The max value is %d" % testga.get_max_value() print "-----------------" if __name__ == '__main__': main() ############################################ 我写了一个简单的测试函数main 运行后多数情况下会产生如下输出 ----------------- Function: y = 0 - 2 * x * x + 12 * x + 5 The best genome is: [0, 0, 1, 1] The variable is: 3 The max value is 23 ----------------- Function: y = 0 - 2 * x * x + 8 * x + 4 The best genome is: [0, 0, 1, 0] The variable is: 2 The max value is 12 ----------------- 以y = 0 - 2 * x * x + 8 * x + 4为例,在Matlab中画出该函数的曲线如下图所示: ![]() 可以看到该函数的极值点确实在x = 2处,证明算法还是相当成功的。 ![]() 其实上边的函数,乘上-1,然后求导也可以知道极值为x=8/4=2,这是极小值,乘上-1就得极大值了。 算是初步改写成功了,当然还有很多问题,比如选择时用的轮盘赌,但是AI的书上的算法似乎有点问题,另外似乎变异操作也有点问题,变异我现在只是变异一处,而原书上则是每一处都根据变异率来进行变异。 种群要设置的稍微大点,太小了没效果。变异率也要大一点。 另外,测试函数里的解空间比较小,还有就是终止条件目前仅判断代数是否超过了设置的最大代数,我想还应该在判断适应性分数最高的地方设置终止条件。这样就避免了多余的运算 |