遗传算法的原理参考维基百科:https://zh.wikipedia.org/wiki/%E9%81%97%E4%BC%A0%E7%AE%97%E6%B3%95
遗传算法流程图:
遗传算法的思想和流程都是很简单的,但是运用在具体应用时却会常常无从下手。如何编码解码,如何进行交叉是两个难点。
遗传算法的最简单例子——寻找函数f(x)=x+5sin(5x)+2cos(4x)在区间[0,10]上的函数最值。
函数图像:
种群规模count=20,染色体长度length=18,进化次数itter_time=10
编码策略是:染色体长度length=18,有2^18个不同组合。那么如何将2^18个不同组合对应到区间[0,10]上呢?
此时对应的解码策略是:V=start+x*(end-start)/(2^length-1),这里start表示区间下限,在此例中即为0;end表示区间上限,在此例中即为10;x为2进制编码的数值;V为解码值,即染色体的真实值;length为染色体长度。
对应代码:
#解码
def decode(x):
y=start+x*(end-start) / (2**length-1)
return y
交叉策略:采用最简单的点交叉策略。
对于两个不同的染色体Xu和Xv,随机得到一个点交叉位置序号mask,mask为(0,length)上的随机整数。
两条染色体进行交叉:
Xu=Xu[0至mask]片段上的基因+Xv[mask至length]片段上的基因
Xv=Xv[0至mask]片段上的基因+Xu[mask至length]片段上的基因
对应代码:
#交叉繁殖
def crossover(parents):
#生成子代的个数,以此保证种群稳定
target_count=count-len(parents)
#孩子列表
children=[]
while len(children)<target_count:
male_index = random.randint(0, len(parents) - 1)
female_index = random.randint(0, len(parents) - 1)
if male_index!=female_index:
male=parents[male_index]
female=parents[female_index]
cross_pos = random.randint(0, length)
mask = 0
for i in range(cross_pos):
mask |= (1 << i)
# 孩子将获得父亲在交叉点前的基因和母亲在交叉点后(包括交叉点)的基因
child = ((male & mask) | (female & ~mask)) & ((1 << length) - 1)
children.append(child)
return children
全部代码:
import numpy as np
import matplotlib.pyplot as plt
import math
import random
# x=np.linspace(-10,10,100)
#
# y=x + 10*np.sin(5*x) + 7*np.cos(4*x)
#GA参数
#查找范围
start=0
end=10
#染色体长度
length=18
#种群数
count=20
#进化次数
itter_time=10
#设置强者的定义概率,即种群前30%为强者
retain_rate=0.3
#设置弱者的存活概率
random_select_rate=0.5
#变异率
mutation_rate=0.2
#目标函数
def aimFunction(x):
y=x+5*math.sin(5*x)+2*math.cos(4*x)
return y
#解码
def decode(x):
y=start+x*(end-start) / (2**length-1)
return y
#获取随机个体,用于生成种群
def gen_chromosome():
"""
随机生成长度为length的染色体,每个基因的取值是0或1
这里用一个bit表示一个基因
"""
chromosome = 0
for i in range(length):
chromosome |= (1 << i) * random.randint(0, 1)
return chromosome
#自然选择
def selection(population):
"""
选择
先对适应度从大到小排序,选出存活的染色体
再进行随机选择,选出适应度虽然小,但是幸存下来的个体
"""
# 对适应度从大到小进行排序
graded = [(aimFunction(decode(chromosome)), chromosome) for chromosome in population]
graded = [x[1] for x in sorted(graded, reverse=True)]
# 选出适应性强的染色体
retain_length = int(len(graded) * retain_rate)
parents = graded[:retain_length]
# 选出适应性不强,但是幸存的染色体
for chromosome in graded[retain_length:]:
if random.random() < random_select_rate:
parents.append(chromosome)
return parents
#交叉繁殖
def crossover(parents):
#生成子代的个数,以此保证种群稳定
target_count=count-len(parents)
#孩子列表
children=[]
while len(children)<target_count:
male_index = random.randint(0, len(parents) - 1)
female_index = random.randint(0, len(parents) - 1)
if male_index!=female_index:
male=parents[male_index]
female=parents[female_index]
cross_pos = random.randint(0, length)
mask = 0
for i in range(cross_pos):
mask |= (1 << i)
# 孩子将获得父亲在交叉点前的基因和母亲在交叉点后(包括交叉点)的基因
child = ((male & mask) | (female & ~mask)) & ((1 << length) - 1)
children.append(child)
return children
#变异
def mutation(children):
for i in range(len(children)):
if random.random() < mutation_rate:
j = random.randint(0, length-1)
population[i] ^= 1 << j
#得到最佳纯输出结果
def get_result(population):
graded = [(aimFunction(decode(chromosome)), decode(chromosome)) for chromosome in population]
graded = [x for x in sorted(graded, reverse=True)]
print(graded[0][0],graded[0][1])
#开始遗传算法
#初始化种群,随机性得到种群
population=[gen_chromosome() for i in range(count)]
i=0
while i<itter_time:
#选择繁殖个体群
parents=selection(population)
#交叉繁殖
children=crossover(parents)
#变异操作
mutation(children)
#更新种群
population=parents+children
get_result(population)
i=i+1