人工智能 遗传算法
题目
用遗传算法求解函数
20 + (x ^ 2) + (y ^ 2) - 10 * (cos(2 * π * x) + cos(2 * π * y)) (-5 < x, y <5)
的最小值
思路
分析问题,确定了至少需要两个类,即种群(Group)与个体(Individual)。同时为了稍微提高一点泛用性,还增加了一个函数(Function)类存放要求解的函数的相关信息。
class Group:
def __init__(self, group_size, mutation_rate, crossover_rate, dna_length, function):
'''
构造函数
:param group_size: 种群大小
:param mutation_rate: 变异率
:param crossover_rate: 交叉率
:param dna_length: DNA序列长度,即基因长度
:param function: 要求解的函数
'''
self.group_size = group_size
self.mutation_rate = mutation_rate
self.crossover_rate = crossover_rate
self.function = function
self.individuals = [] # 所有个体
self.best_individual = None # 最优个体
self.dna_length = dna_length
self.init_group()
class Individual:
def __init__(self, gene):
'''
构造函数
:param gene: 基因序列
'''
self.gene = gene
self.fit = 0 # 适应度
class Function:
def __init__(self, function, max_variable, min_variable, find_min=True):
'''
构造函数
:param function: 要求解的函数
:param max_variable: 函数自变量的最大值
:param min_variable: 函数自变量的最小值
:param find_min: 求最小值,默认为True,False即为求最大值
'''
self.function = function
self.max_variable = max_variable
self.min_variable = min_variable
self.find_min = find_min
首先需要构造一个种群,在构造函数为各种变量赋初值,然后进行初始化种群操作,即为种群中的所有个体创建基因序列
def generate_gene(self):
'''
生成一个基因序列
:return: 返回一个由0,1组成的序列
'''
gene = []
for i in range(self.dna_length):
gene.append(random.randint(0, 1))
return gene
def init_group(self):
'''
初始化种群的所有个体
'''
for i in range(self.group_size):
self.individuals.append(Individual.Individual(self.generate_gene()))
然后就要开始繁衍获得下一代
获得下一代需要经过以下两个步骤
- 产生孩子
种群中的每一个个体与种群中的另一个随机个体繁衍获得孩子。暂时先默认孩子接收父亲的基因。但是繁殖过程中孩子的基因可能发生交叉和变异。
交叉:从孩子的基因的一个随机位置开始,该位置后的基因变为母亲在同样位置之后的基因
变异:孩子的基因的某个随机位置取反
def crossover(self, father, mother):
'''
交叉
:param father: 父亲
:param mother: 母亲
:return: 孩子
'''
gene = [i for i in father.gene] # 首先默认孩子接收父亲的基因
child = Individual.Individual(gene) # 直接传入father.gene会导致更改child的基因时father的基因也会修改,种群基因变得不稳定
if self.crossover_rate > random.random(): # 判断是否发生交叉
cross_point = random.randint(1, self.dna_length - 1) # 交叉发生的位置
child.gene[cross_point:] = mother.gene[cross_point:] # 交叉位置后的基因变为母亲的基因
return child
def muter(self, individual):
'''
变异
:param individual: 可能变异的个体
:return: 变异之后的个体或原个体
'''
if self.mutation_rate > random.random(): # 判断是否变异
index = random.randint(0, self.dna_length - 1) # 变异的位置
individual.gene[index] = 1 - individual.gene[index] # 取反
return individual
def get_child(self, father, mother):
'''
产生一个孩子
:param father: 父亲
:param mother: 母亲
:return: 孩子
'''
child = self.crossover(father, mother)
child = self.muter(child)
return child
- 自然选择
此时的个体数已经变为原本的两倍,接下来要进行选择。选择适应度较高的一半个体存活。
首先计算所有个体的适应度
个体的适应度用函数的计算结果表示,但个体的基因是0,1组成的序列,无法直接带入到函数的自变量中求解,所以需要先把个体的基因转换