遗传算法(GA)的原理简介与应用【python实现】
- 算法原理简介与实现
- 算法框架
- 关于GA求解过程中一些结果的讨论
- SA-GA总结与体会
算法原理简介与实现 遗传算法(Genetic Algorithm,GA)是模拟达尔文生物进化论的自然选择和遗传学机理的生物进化过程的计算模型,是一种通过模拟自然进化过程搜索最优解的方法。
遗传算法是从代表问题可能潜在的解集的一个种群(population)开始的,而一个种群则由经过基因(gene)编码的一定数目的个体组成。每个个体实际上是染色体(chromosome)带有特征的实体。染色体作为遗传物质的主要载体,即多个基因的集合,其内部表现(即基因型)是某种基因组合,它决定了个体的形状的外部表现,如黑头发的特征是由染色体中控制这一特征的某种基因组合决定的。因此,在一开始需要实现从表现型到基因型的映射即编码工作。由于仿照基因编码的工作很复杂,我们往往进行简化,如二进制编码,初代种群产生之后,按照适者生存和优胜劣汰的原理,逐代(generation)演化产生出越来越好的近似解,在每一代,根据问题域中个体的适应度(fitness)大小选择(selection)个体,并借助于自然遗传学的遗传算子(genetic operators)进行组合交叉(crossover)和变异(mutation),产生出代表新的解集的种群。这个过程将导致种群像自然进化一样的后生代种群比前代更加适应于环境,末代种群中的最优个体经过解码(decoding),可以作为问题近似最优解。
【机器学习|遗传算法(GA)的原理简介与应用【python实现】】下面通过求解与上一篇文章(点击可跳转)相同的一个问题来进一步说明算法介绍和实现过程:
算法框架
- 确定编码与解码方式。常见的编码方式有二进制编码、整数编码、顺序编码等,具体的编码方式的选择需要根据需要解决的问题来选择。
在本题中,采用二进制编码的方式。为了保证编码后对应的数值在可行域范围内,采取了编码后再进行一步线性变换的操作。
编码方式 | 适用问题 |
---|---|
二进制编码 | 背包问题、函数优化问题、指派问题 |
整数编码 | 时间优化问题 |
顺序编码 | 指派、旅行商(TSP)问题,调度问题 |
- 交叉变异的方式交叉和变异能够保证种群的多样性。交叉是指一对父代个体之间染色体进行交叉,交叉率通常设为0.8-0.9,用pc表示。对于二进制及整数编码,交叉方式有单切点交叉、双切点交叉、均匀交叉;对于顺序编码,有部分映射交叉、顺序交叉和循环交叉,这些方式可保证交叉的合法性。
变异是指染色体上的基因发生突变,在生物群体中发生概率较小,因此变异率设定在0.05一下,用pm表示。对于二进制及整数编码,变异方式为位变异;对于顺序编码,变异方式有插入、交换、翻转。
- 进行适应度的计算与标定。一般来说,适应度可以以所求目标函数值作为参考,对目标函数值域的某种映射变换称为适应度标定。适应度标定很重要,直接影响算法收敛速度以及是否可以找到最优解。下面介绍两种常用标定方法。
动态线性标定: F = a k f + b k F=a^kf+b^k F=akf+bk, k k k为迭代次数, F F F为适值函数, f f f为目标函数。对于 m a x f ( x ) maxf(x) maxf(x),则 F = f ? f m i n k + ξ k F=f-f_{min}^k+\xi^k F=f?fmink?+ξk;对于 m i n f ( x ) minf(x) minf(x),则 F = ? f + f m a x k + ξ k F=-f+f_{max}^k+\xi^k F=?f+fmaxk?+ξk。其中 ξ 0 = 0 \xi^0=0 ξ0=0, ξ k = ξ k ? 1 ? r \xi^k=\xi^{k-1}*r ξk=ξk?1?r, r ∈ [ 0.9 , 0.999 ] r\in[0.9,0.999] r∈[0.9,0.999]。关于 ξ k \xi^k ξk,可以认为 ξ k \xi^k ξk的加入使得使最坏个体仍有繁殖的可能,它的值随 k k k的增大而减小,更加符合自然界的规律。
- 确定选择策略,优胜劣汰。基本思想是:各个个体被选中的概率与其适应度大小成正比。常用的选择方法有轮盘赌选择法、随即遍历抽样法和精英保留策略。
轮盘赌,顾名思义是通过转盘,随机选取个体,即指针落到某一个个体对应的累积适应度区间内,即选择该个体。这可以通过生成[0,1)伪随机数,然后找到该伪随机数的对应区间,即可确定选择的个体。
随机遍历抽样是假定有 n n n个需要选择的个体,那么选择个体的指针就有 n n n个,指针之间的距离为 1 n \frac{1}{n} n1?,第一个指针在[0, 1 n \frac{1}{n} n1?]随机确定。本题采用了轮盘赌的选择策略。
- 开始进化。
SA-GA总结与体会
求解方法 | 最优点 | 函数值 |
---|---|---|
Matlab求解 | ( ? 1.62 , 3.04 ) , ( ? 1.62 , ? 3.04 ) (-1.62,3.04),(-1.62,-3.04) (?1.62,3.04),(?1.62,?3.04) | 41.3205 |
模拟退火(SA) | ( ? 1.5449 , ? 3.1257 ) (-1.5449,-3.1257) (?1.5449,?3.1257) | 41.3472 |
遗传算法(GA) | ( ? 1.569 , ? 3.104 ) (-1.569,-3.104) (?1.569,?3.104) | 41.334 |
python实现的GA代码如下:
import random
import math
import numpy as np
import matplotlib.pyplot as pltpopulation_size = 50 #种群大小
generation = 200 #代数
code_len = 10 #二进制编码长度
pc = 0.6# 交配概率
pm = 0.01# 变异概率
gene_population_1 = [] #种群的基因库
decode_value_1 = [] #解码后的变量
gene_population_2 = [] #种群的基因库
decode_value_2 = [] #解码后的变量
fitness = [] #函数值(原始适应值)
fitness_standard = [] #标定后适应值
select_possibility = []
sum_pob = []
random_selection = []
def encode(gene_population):
for i in range(population_size):
gene = []
for j in range(code_len):
gene.append(random.randint(0,1))
gene_population.append(gene)
#print(gene_population)def decode(gene_population,decode_value):
decode_value.clear()
for i in range(population_size):
value = https://www.it610.com/article/0
for j in range(code_len):
value = value + gene_population[i][j] * (2 ** (code_len - 1 - j))
value = value * 10 / (2 ** (code_len) - 1) - 5
decode_value.append(value)
#适应值的处理可以再考虑一下
def fitness_process(decode_value_1,decode_value_2):
fitness.clear()
fitness_standard.clear()
sum_fitness = 0
for i in range(population_size):
#function = - (decode_value_1[i] - 1)**2- (decode_value_2[i] - 1)**2 + 1 #测试
function = -(6*decode_value_1[i]/(2 + decode_value_1[i] ** 2 + decode_value_2[i] ** 2) + 5*math.sin(decode_value_1[i]) +3*math.cos(decode_value_2[i]) + 50)
fitness.append(function)
fitness_standard.append(function)
#找最小值
min_fitness = fitness[0]
#min_id = 0
for k in range(population_size):
if (min_fitness> fitness[k]):
min_fitness = fitness[k]
#min_id = k
#适应值修正————线性标定
zeta = 2
#tao = 0.95
for m in range(population_size):
fitness_standard[m] = fitness[m] - min_fitness + zeta
#zeta = zeta ** (tao)#找最大值
max_fitness = fitness_standard[0]
max_id = 0
for j in range(population_size):
sum_fitness = sum_fitness + fitness_standard[j]
if (max_fitness < fitness_standard[j]):
max_fitness = fitness_standard[j]
max_id = j
return (sum_fitness,max_id)def roulette_select(sum_fitness,gene_population):
sum_pob.clear()
random_selection.clear()
for i in range (population_size):
possibility = fitness_standard[i]/sum_fitness
select_possibility.append(possibility)
pob = 0for i in range(population_size):
pob = pob + select_possibility[i]
sum_pob.append(pob)
sum_pob[-1]=1
for i in range(population_size):
random_selection.append(random.random())
#random_selection.sort()gene_population_new = []
#random_selection_id = 0
#for i in range(population_size):
#while(( random_selection_id < population_size) and (random_selection[random_selection_id] < sum_pob[i])):
#gene_population_new.append(gene_population[i])
#random_selection_id += 1
#轮盘赌
for i in range(population_size):
for j in range(population_size):
if((random_selection[i]>sum_pob[j])and(random_selection[i]<=sum_pob[j + 1])):
gene_population_new.append(gene_population[j + 1])
gene_population = gene_population_new# 进行基因的变异
def mutation(gene_population):
for i in range(population_size):
if random.random() < pm:
mutation_point = random.randint(0, code_len - 1)
if gene_population[i][mutation_point] == 0:
gene_population[i][mutation_point] = 1
else:
gene_population[i][mutation_point] = 0# 进行交配过程
def crossover(gene_population):
for i in range(0, population_size - 1, 2):
if random.random() < pc:
# 随机选择交叉点
change_point = random.randint(0, code_len - 1)
temp1 = []
temp2 = []
temp1.extend(gene_population[i][0: change_point])
temp1.extend(gene_population[i+1][change_point:])
temp2.extend(gene_population[i+1][0: change_point])
temp2.extend(gene_population[i][change_point:])
gene_population[i] = temp1
gene_population[i+1] = temp2#开始进化
best_fitness_all = []
best_fitness_all.append(0)encode(gene_population_1)
encode(gene_population_2)
for i in range(generation):
decode(gene_population_1,decode_value_1)
decode(gene_population_2,decode_value_2)
sum_fitness,max_id = fitness_process(decode_value_1,decode_value_2)
best_fitness_all.append(-fitness[max_id])roulette_select(sum_fitness,gene_population_1)
roulette_select(sum_fitness,gene_population_2)
crossover(gene_population_1)
mutation(gene_population_1)
crossover(gene_population_2)
mutation(gene_population_2)
print('(x1,x2)为(%s,%s),最小值为%s'%(decode_value_1[max_id],decode_value_2[max_id],-fitness[max_id]))plt.plot(range(1, len(best_fitness_all)+1), best_fitness_all)
plt.xlabel('最优解更新次数',fontproperties='SimHei')
plt.ylabel('每一代的最优解', fontproperties='SimHei')
plt.show()
推荐阅读
- 机器学习|遗传算法与matlab实现 Genetic Algorithm
- 优化算法|遗传算法Python代码实现
- 遗传算法|遗传算法(GA)原理以及matlab与python实现
- #|达尔文与老子的对话【伏羲八卦图】(Python&Matlab实现)
- 笔记|工业缺陷检测项目实战(一)——基于opencv的工件缺陷检测C++实现
- python|opencv-python 入门实战(传统方法Hog+svm实现目标检测)
- 图像处理|【OpenCV-Python】(调用电脑摄像头+读取视频)
- 计算机视觉|10分钟学会使用YOLO及Opencv实现目标检测
- 每日算法之数组(一)