目的:
基于遗传算法编写程序实现字符串显示以及实践遗传算法应用,理解求解流程并测试主要参数对结果的影响。
代码:
import random
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
POPULATION_SIZE = 200
GENES = '''abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ 1234567890, .-;:_!"#%&/()=?@${[]}'''
TARGET = "Hello, world!"
MUTATION_PROBABILITY = 0.05
class Individual(object):
def __init__(self, chromosome):
self.chromosome = chromosome
self.fitness = self.__calculate_fitness()
@classmethod
def mutated_genes(cls):
return random.choice(GENES)
@classmethod
def create_gnome(cls):
return [cls.mutated_genes() for _ in range(len(TARGET))]
def mate(self, other):
child_chromosome = []
for i in range(len(self.chromosome)):
prob = random.random()
if prob < 0.45:
child_chromosome.append(self.chromosome[i])
elif prob < 0.90:
child_chromosome.append(other.chromosome[i])
else:
child_chromosome.append(self.__class__.mutated_genes())
return Individual(child_chromosome)
def __calculate_fitness(self):
fitness = 0
for i in range(len(self.chromosome)):
if self.chromosome[i] != TARGET[i]:
fitness += 1
return fitness
def main():
generation = 1
population = [Individual(Individual.create_gnome()) for _ in range(POPULATION_SIZE)]
while True:
population = sorted(population, key=lambda x: x.fitness)
if population[0].fitness == 0:
break
new_generation = []
s = int((10 * POPULATION_SIZE) / 100)
new_generation.extend(population[:s])
s = int((90 * POPULATION_SIZE) / 100)
for _ in range(s):
parent1 = random.choice(population[:50])
parent2 = random.choice(population[:50])
child = parent1.mate(parent2)
new_generation.append(child)
population = new_generation
print("Generation: {}\tString: {}\tFitness: {}".format(generation, "".join(population[0].chromosome), population[0].fitness))
generation += 1
print("Generation: {}\tString: {}\tFitness: {}".format(generation, "".join(population[0].chromosome), population[0].fitness))
if __name__ == '__main__':
main()
结果与分析:
运行流程:
首先定义了一个 Individual 类,表示一个个体。每个个体都有一条染色体,即由基因组成的字符串(长度与目标字符串相同)。在创建个体时,将随机生成一条染色体,并计算其适应度(即与目标字符串不同字符的数量)。
Individual 类有两个类方法,分别是 mutated_genes 和 create_gnome。mutated_genes 方法会返回一个随机的基因,用于基因突变。create_gnome 方法则是生成一个由随机基因组成的染色体。
在个体进行繁殖时,会根据概率选择基因来构造下一代。如果随机数小于 0.45,则从自己的染色体中选取基因;如果随机数小于 0.90,则从另一个个体的染色体中选取基因;否则则发生基因突变,即随机生成一个新的基因。
在主函数 main 中,首先生成一个初始种群(由若干个个体组成)。然后在循环中,对种群进行排序,选择适应度高的个体作为父母,进行繁殖,生成下一代种群。在选择父母时,可以从适应度排名前 50% 的个体中随机选择两个。新一代种群中,将包含上一代适应度最高的 10% 的个体(精英保留策略),以及 90% 的通过繁殖产生的新个体。循环终止条件是找到一个适应度为 0 的个体,即染色体与目标字符串相等。最后输出找到的字符串以及其适应度。
分析:经过多轮迭代,最终找到了适应度为0的染色体,即与目标字符串完全相等的串 "Hello, world!",并输出了其所在的代数以及适应度。从结果来看,遗传算法在寻找字符串问题上表现出了较好的效果,最多经过了16轮迭代就找到了目标字符串
小结
遗传算法是一种有效的演化计算方法,通过基因突变、交叉和选择等方式,在不断演化的种群中寻找符合目标要求的个体,最终达到解决问题的目的。在实现了遗传算法的基础上,我们可以通过改变适应度函数、调整参数等手段来进一步提高算法的效率和准确性。