利用 Python 实现 遗传算法(GeneticAlgorithm)
悠扬的幻想天空 - 博客
December 10, 2018 日常 • 作者:悠扬
要求:
核心代码:
1、生成初代
我采用的是2进制来表示染色体,先随机出一堆0和1的列表
def getFisrtGroup(group_size, chrom_length):
group = []
for i in range(group_size):
temp = []
for j in range(chrom_length):
temp.append(random.randint(0, 1))
group.append(temp)
return group
2、GA循环
for i in range(generation):
obj_value = calobjValue(group, chrom_length, max_value, min_value, divid) # 个体评价
fit_value = calfitValue(obj_value) # 获取群体适应值
best_individual, best_fit = best(group, fit_value) # 返回最优基因, 最优适应值
if( abs(f(xx)+186.730909) < 0.000001):#找到最优解
crossover(group, fit_value, pc) # 交配
mutation(group, pm) # 变异
3、解码
div代表每个参数的开始位置和末尾位置,方便分隔参数。这个函数会返回一个包含参数的列表。
'''
b 染色体
chrom_length 染色体长度
max_value,min_value 最大最小值
div 分割
'''
def b2d(b, chrom_length, max_value, min_value, div):
rwno = []
for i in range(len(div)):
。。。
for j in range(star, end):
t += b[j] * (math.pow(2, j - star))
t = t * max_value / (math.pow(2, end - star + 1) - 1) - min_value
rwno.append(t)
return rwno
5、获取适应值
因为都是求函数最小值,所以我用的是e^(-x)这个函数来表示适应值,当计算结果减去预估的最小值,结果越逼近1就代表计算结果离最小值越近。
#适应函数
def s(x):
return math.exp(-abs(x-1))
6、选择交叉方案
我用的是轮盘选择,先求出每个子代的适应值的占比,然后把它们按它的占比分在[0, 1]的区间上面,随机出0到1的随机数,看看这个随机数落在谁的上面。
# 转轮盘选择法
def selection(group, fit_value):
newfit_value = [] #[ [[染色体], [锚点]],... ]
newgroup = [] #[ [父], [母], [父], [母],....]
# 适应度总和
total_fit = sum_fit(fit_value)
# 设置各个的锚点
t = 0
for i in range(len(group)):
t += fit_value[i]/total_fit
newfit_value.append([group[i], t])
# 转轮盘选择法
for i in range(len(newfit_value)):
parents = len(newfit_value) # 初始化指针
r = random.random() #指针
for j in range(len(newfit_value)):#看看指针指到睡了
if newfit_value[j][1] > r:
parents = j
break
newgroup.append(newfit_value[parents][0])
return newgroup
7、交配
先用上面的轮盘选出一堆父代母代,然后开始交叉。
def crossover(group, fit_value, pc):
parents_group = selection(group, fit_value) #[ [[父], [母]],....]
group_len = len(parents_group)
for i in range(0, group_len, 2):
if(random.random() < pc): # 看看是否要交配
cpoint = random.randint(0, len(parents_group[0])) # 随机交叉点
。。。
∞、繁衍
继续重复计算适应值→选择→交配的过程模拟物竞天择适者生存的遗传算法,直到推衍出想要的结果。
计算结果:
generation = 1000 # 繁衍代数
group_size = 2000 # 染色体数量,偶数
chrom_length = 500 # 染色体长度
找出两个最优解:
[2.3566456537597764, 2.3564076733830963]
[0.7849757859540485, 2.3563759723412123]
精确到小数点后六位:
F(x) = 1.0000002663624468
x = [0.7851439319246674, 2.356238727907994]
染色体 = [0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1,1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1,0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1]
适应值 = 0.9999997336375888
代数 = 839
在839代时候出现想要的精确到小数点后6位的解。
最后
感觉遗传算法挺玄学的,开局一串随机数,全靠变异,还容易陷入局部最优解的状况。如果有大致函数图像,可以尝试把初代种群洒在一个全局最优解的附近,这样开局就是高富帅了。变异几率高的话的确可以很快把适应值拉上去,但达到顶峰的时候会有更大的波动,很难得到想要的答案,每次快接近的时候就被一个变异给甩出去了。但是变异几率不高可能好多代都在原地踏步,我想到的解决方案就是,一开始变异几率高,先把适应值升高到一定程度之后,在把变异几率给调下来,这样就可以稍稍解决刚才说到的起步慢、波动大的两个问题。还有就是如果检测到发现自己陷入局部最优解(或者说长期适应值不增长),可以再次把变异几率调高来逃脱。如果染色体数量太多,会拖慢适应改变速度,染色体长度同理,交配几率的影响大概和变异几率一样吧。