python学智能算法(四)|遗传算法:原理认识和极大值分析
【1】引言
前述已经对模拟退火算法进行了一些探索,相关文章链接为:
python学智能算法(一)|模拟退火算法:原理解释和最小值求解-CSDN博客
python学智能算法(二)|模拟退火算法:进阶分析-CSDN博客
python学智能算法(三)|模拟退火算法:深层分析-CSDN博客
遗传算法相对于模拟退火算法,稍微复杂一些。整体上,遗传算法会不断修改一些量,而模拟退火算法只需要对自变量微调。
所以,在学习了模拟退火算法之后,学习遗传算法会更加高效。
【2】原理解释
生物进化过程中,需要把遗传信息传递给新一代。
遗传信息在传递给给新一代的时候,除了复制上一代的相关内容,还会因为环境或者其他因素而发生变异;新一代在对自然的适应过程中,也会出现优胜劣汰;所以最后剩下来的,大概率是具备先辈特征,但又发生过变异,且适应环境的优势个体。
生物的进化,本质上其实是遗传信息的进化。
实际的进化过程,往往是父本和母本的遗传信息进行融合的过程。
所以综合下来,生物进化具体的可以分为三个部分:
选择:根据个体对环境的适应程度,优势个体优先获得择偶权,其遗传信息优先被选择;
交叉:优势个体的择偶成果,其实本质上就是父本和母本的排列组合;
变异:新一代产生过程中,遗传信息相对于父本和母本的变化,这种变化支持新一代适应环境的变化和继续成为新的优势个体。
【3】代码实现
为在代码上实现这个过程,需要进一步细化。
【3.1】准备工作
首先引入必要的模块:
import random #引入random模块
import matplotlib.pyplot as plt #引入matplotlib模块
import numpy as np #引入numpy模块
然后需要定义一些参数,这些参数有一些暂时还不能理解,所以之后会解释:
# 参数设置
pop_size = 50 # 种群大小
generations = 100 # 迭代次数
tournament_size = 5 # 锦标赛选择的参赛个体数量
mutation_rate = 0.1 # 变异概率
min_val = 0 # 变量的最小值
max_val = 10 # 变量的最大值
然后先把目标函数画出来,这一步的目的是提前知晓目标函数的图形以辅助理解:
#绘制目标函数图
#定义自变量
x=np.linspace(min_val,max_val,1000)
#定义因变量
y=- (x - 2) ** 2 + 10
#绘图
plt.plot(x,y)
plt.show()
【3.2】子函数定义
然后需要定义多个子函数:
【3.2.1】目标函数
# 目标函数
def target_function(x):
return - (x - 2) ** 2 + 10
【3.2.2】初始化种群
# 初始化种群
def initialize_population(pop_size, min_val, max_val):
return [random.uniform(min_val, max_val) for _ in range(pop_size)]
这个函数的功能是,生成pop_size个随机数,随机数的范围是[min_val,max_val]。不过这个随机数的生成不是一次全都生成,而是生成pop_size次。
【3.2.3】计算适应度
# 计算适应度
def fitness(individual):
return target_function(individual)
这个函数的功能是,将individual代入目标函数。
【3.2.4】选择操作
# 选择操作(锦标赛选择)
def tournament_selection(population, tournament_size):
tournament = random.sample(population, tournament_size)
return max(tournament, key=fitness)
这个函数的功能是,应用random.sample()函数,在population这个数组中,按照不重复的规则取tournament_size个数字,这些取出来的数字存储在tournament里;之后函数会将tournament里的数字代入适应度函数进行计算,并返回所有计算值里面的最大值。
【3.2.5】交叉操作
# 交叉操作(简单算术交叉)
def crossover(parent1, parent2):
alpha = random.random()
child = alpha * parent1 + (1 - alpha) * parent2
return child
这个函数的功能是,先应用random.random()函数生成[0,1)之间的随机数,然后以随机数作为第一个参数parent1的比例,以(1-随机数)作为第二个参数parent2的比例让这两个参数混合。
【3.2.6】变异操作
# 变异操作
def mutation(individual, mutation_rate, min_val, max_val):
if random.random() < mutation_rate:
# 简单的变异,在一定范围内随机扰动
individual += random.uniform(-1, 1)
# 确保变异后的个体在合法区间内
individual = max(min_val, min(individual, max_val))
return individual
这个函数的功能是,先约定一个变异率mutation_rate,然后给出变异后学的上下限[min_val, max_val],理解为只有处于这个变异区间内的个体才有可能适应环境。发生变异必须有一个原始起点,所以必须从外界再输入一个参数individual作为原始起点。
原始起点individual发生变异的前提条件是应用randm.random()函数生成的随机数小于变异率mutation_rate;变异的程度等于random.uniform随机生成一个位于[-1, 1]中的数据;之后套了一层限定,要求新的变异个体要位于上下限[min_val, max_val]其中才会正常输出。
【3.3】遗传算法函数
# 遗传算法主函数
def genetic_algorithm(pop_size, generations, tournament_size, mutation_rate, min_val, max_val):
population = initialize_population(pop_size, min_val, max_val)
for _ in range(generations):
new_population = []
for _ in range(pop_size):
parent1 = tournament_selection(population, tournament_size)
parent2 = tournament_selection(population, tournament_size)
child = crossover(parent1, parent2)
child = mutation(child, mutation_rate, min_val, max_val)
new_population.append(child)
population = new_population
best_individual = max(population, key=fitness)
best_fitness = fitness(best_individual)
return best_individual, best_fitness
前述的子函数都定义好之后,到了最核心的遗传算法函数,这个函数将逐步调用之前的子函数。
首先,将调用【3.2.2】节的初始化种群函数,生成pop_size个随机数,随机数的范围是[min_val,max_val];
然后,会在for循环中实现遗传信息的进化,可以记作代际循环。
而在每一代的传承中,会再次应用for循环,可以理解为代内循环。此时的循环过程需要反复运行其余子函数。
具体的for循环中,对于每一个代,需要循环和整个种群相同大小的次数。每次循环的操作具体有:分别应用【3.2.4】节选择操作挑选出数量相等的父本和母本(parent1和partent2具体由谁作为父本没有影响);然后由父本和母本按照【3.2.5】节交叉操作生成新一代child;新一代的实际诞生过程又需要按照【3.2.6】节变异操作来增加变异。
代际循环内部的代内循环会生成很多新的子代,这些子代需要在每一代没都挑选出最大值,并将这个最大值代回目标函数做适应度分析。
【3.4】输出
# 运行遗传算法
best_x, best_fitness = genetic_algorithm(pop_size, generations, tournament_size, mutation_rate, min_val, max_val)
print(f"最优解 x = {best_x},最大值 f(x) = {best_fitness}")
之后直接输出运行结果即可。
图1 目标函数
由图1可见,极大值应该在(2,10)处取得。
刚好,控制台输出的极大值也是这样:
图2 控制台极大值结果
此时的完整代码为:
import random #引入random模块
import matplotlib.pyplot as plt #引入matplotlib模块
import numpy as np #引入numpy模块
# 参数设置
pop_size = 50 # 种群大小
generations = 100 # 迭代次数
tournament_size = 5 # 锦标赛选择的参赛个体数量
mutation_rate = 0.1 # 变异概率
min_val = 0 # 变量的最小值
max_val = 10 # 变量的最大值
#绘制目标函数图
#定义自变量
x=np.linspace(min_val,max_val,1000)
#定义因变量
y=- (x - 2) ** 2 + 10
#绘图
plt.plot(x,y)
plt.show()
# 目标函数
def target_function(x):
return - (x - 2) ** 2 + 10
# 初始化种群
def initialize_population(pop_size, min_val, max_val):
return [random.uniform(min_val, max_val) for _ in range(pop_size)]
# 计算适应度
def fitness(individual):
return target_function(individual)
# 选择操作(锦标赛选择)
def tournament_selection(population, tournament_size):
tournament = random.sample(population, tournament_size)
return max(tournament, key=fitness)
# 交叉操作(简单算术交叉)
def crossover(parent1, parent2):
alpha = random.random()
child = alpha * parent1 + (1 - alpha) * parent2
return child
# 变异操作
def mutation(individual, mutation_rate, min_val, max_val):
if random.random() < mutation_rate:
# 简单的变异,在一定范围内随机扰动
individual += random.uniform(-1, 1)
# 确保变异后的个体在合法区间内
individual = max(min_val, min(individual, max_val))
return individual
# 遗传算法主函数
def genetic_algorithm(pop_size, generations, tournament_size, mutation_rate, min_val, max_val):
population = initialize_population(pop_size, min_val, max_val)
for _ in range(generations):
new_population = []
for _ in range(pop_size):
parent1 = tournament_selection(population, tournament_size)
parent2 = tournament_selection(population, tournament_size)
child = crossover(parent1, parent2)
child = mutation(child, mutation_rate, min_val, max_val)
new_population.append(child)
population = new_population
best_individual = max(population, key=fitness)
best_fitness = fitness(best_individual)
return best_individual, best_fitness
# 运行遗传算法
best_x, best_fitness = genetic_algorithm(pop_size, generations, tournament_size, mutation_rate, min_val, max_val)
print(f"最优解 x = {best_x},最大值 f(x) = {best_fitness}")
【4】原理分析
在完成第一轮代码解析之后,可以再回头看核心的遗传算法代码:
# 遗传算法主函数 def genetic_algorithm(pop_size, generations, tournament_size, mutation_rate, min_val, max_val): population = initialize_population(pop_size, min_val, max_val) for _ in range(generations): new_population = [] for _ in range(pop_size): parent1 = tournament_selection(population, tournament_size) parent2 = tournament_selection(population, tournament_size) child = crossover(parent1, parent2) child = mutation(child, mutation_rate, min_val, max_val) new_population.append(child) population = new_population best_individual = max(population, key=fitness) best_fitness = fitness(best_individual) return best_individual, best_fitness
核心的遗传算法代码一共有两层,代际循环和代内循环(这两个名词为本文临时起意,没有出处,如有雷同,纯属巧合)。
代际循环是从for _ in range(generations)到best_individual = max(population, key=fitness)这一段,代际循环的的目的是输出best_individual和best_fitness,这是两个值,为了获得这两个值,需要在代内循环。
代内循环是从for _ in range(pop_size)到population = new_population这一段,代内循环的的目的是输出new_population,这是一组数,为了获得这组数,代内循环先挑选了优势的父母,然后父母的遗传信息进行交叉,然后再叠加了变异,这样才会产生一系列新的子代new_population.append(child)。
代际循环从每一代中挑选最优的子代max(population, key=fitness),然后把子代代入适应度函数(目标函数),由此实现极大值的获取。
本质上,需要注意的是,种群数量pop_size和代际数量generations本身不会参与计算,它们只是合起来约束了总计算次数。
和模拟退火算法相比,遗传算法的自变量变化过程相对更复杂,是选择、交叉和变异三种方法的综合效果,模拟退火算法的自变量变化过程可以大致理解为只有变异一种方法。
遗传算法在本质上依然是让函数在点的附近进行邻域搜索,这是新一代产生的过程,由于代际的存在,每一代都在重复进行邻域搜索,所以整个自变量区间都会被覆盖,极值自然会被发现。
【5】代码改写
为了显示具体的运算过程,所以需要读取每次运算的最佳子代值和对应最佳适应度值,需要改写遗传算法代码:
# 遗传算法主函数
def genetic_algorithm(pop_size, generations, tournament_size, mutation_rate, min_val, max_val):
population = initialize_population(pop_size, min_val, max_val)
best_individual_history=[]
best_fitness_history=[]
for _ in range(generations):
new_population = []
for _ in range(pop_size):
parent1 = tournament_selection(population, tournament_size)
parent2 = tournament_selection(population, tournament_size)
child = crossover(parent1, parent2)
child = mutation(child, mutation_rate, min_val, max_val)
new_population.append(child)
population = new_population
best_individual = max(population, key=fitness)
best_fitness = fitness(best_individual)
best_individual_history.append(best_individual)
best_fitness_history.append(best_fitness)
这里是在代内循环就完成了最佳值的提取,而之前这个提取是在代际循环中完成的。
之后就是把提取到的参数best_individual, best_fitness,best_individual_history,best_fitness_history用图像表示出来,需要注意的是:best_individual和best_fitness分别只代表一个数,best_individual_history和best_fitness_history分别代表一个列表,是一组数。
plt.suptitle('遗传算法', y=0.95) # 设置图像名称
plt.subplot(1,3,1)
x = np.linspace(min_val , max_val, 1000)
y = target_function(x)
plt.plot(x, y, label='目标函数')
frame = len(best_individual_history)
x1 = best_individual_history[:frame + 1]
y1 = best_fitness_history[:frame + 1]
plt.scatter(x1, y1, c='b', label='最佳子代解与最佳适应度')
best_x=best_individual
best_y=best_fitness
plt.scatter(best_x, best_y, c='r',marker='^', label='最佳适应度')
plt.legend(loc='upper left')
plt.subplot(1,3,2)
frame = len(best_individual_history)
x1 = best_individual_history[:frame + 1]
y1 = best_fitness_history[:frame + 1]
plt.scatter(x1, y1, c='b', label='最佳子代解与最佳适应度')
plt.legend()
plt.subplot(1,3,3)
Calculation_numbers = np.arange(1, generations + 1)
plt.plot(Calculation_numbers, best_fitness_history, c='r',marker='o',label='计算次数-适应度')
plt.xlabel('计算次数')
plt.ylabel('适应度')
plt.legend()
plt.tight_layout()
plt.show()
这里使用了最简单的plt.subplot()多图形式来表达。
Calculation_numbers = np.arange(1, generations + 1)是将计算次数从1开始记,np.arange(1, generations + 1)刚好只能取值到generations,所以这个数字的量刚好也和best_fitness_history数组中所含有的数字的量相对应。
代码运行后获得的图像为:
图3 遗传算法运算过程图解
图3是使用了plt.tight_layout()强行把图像隔开了,所以有些图例和图像交叉在一起,如果去除该行代码,会有:
图4 遗传算法运算过程图解改
此时对应的控制台输出为:
最优解 x = 9.120261411809624,最大值 f(x) = 91.40042672132924
best_individual_history= [9.07295498726787, 9.126795596996477, 9.118238756728179, 9.119005229189478, 9.120186007065081, 9.120322461780129, 9.120229259859254, 9.120271697555289, 9.120257451291765, 9.120261411809624]
best_fitness_history= [89.09500548890338, 91.35590447364314, 91.39616707455154, 91.39878387042377, 91.40042084910132, 91.40042279667345, 91.40042566626923, 91.40042660409392, 91.40042670768791, 91.40042672132924]
此时的完整代码为:
import random #引入random模块
import matplotlib.pyplot as plt #引入matplotlib模块
import numpy as np #引入numpy模块
import matplotlib.animation as animation
# 设置 matplotlib 支持中文
plt.rcParams['font.family'] = 'SimHei'
# 解决负号显示问题
plt.rcParams['axes.unicode_minus'] = False
# 参数设置
pop_size = 50 # 种群大小
generations = 10 # 迭代次数
tournament_size = 5 # 锦标赛选择的参赛个体数量
mutation_rate = 0.1 # 变异概率
min_val = 0 # 变量的最小值
max_val = 10 # 变量的最大值
# 目标函数
def target_function(x):
#return - (x - 2) ** 2 + 10
#return x+10*np.sin(5*x)+7*np.cos(4*x)
return x ** 2 * np.sin(5 * x) + 0.1 * x ** 2
# 初始化种群
def initialize_population(pop_size, min_val, max_val):
return [random.uniform(min_val, max_val) for _ in range(pop_size)]
# 计算适应度
def fitness(individual):
return target_function(individual)
# 选择操作(锦标赛选择)
def tournament_selection(population, tournament_size):
tournament = random.sample(population, tournament_size)
return max(tournament, key=fitness)
# 交叉操作(简单算术交叉)
def crossover(parent1, parent2):
alpha = random.random()
child = alpha * parent1 + (1 - alpha) * parent2
return child
# 变异操作
def mutation(individual, mutation_rate, min_val, max_val):
if random.random() < mutation_rate:
# 简单的变异,在一定范围内随机扰动
individual += random.uniform(-1, 1)
# 确保变异后的个体在合法区间内
individual = max(min_val, min(individual, max_val))
return individual
# 遗传算法主函数
def genetic_algorithm(pop_size, generations, tournament_size, mutation_rate, min_val, max_val):
population = initialize_population(pop_size, min_val, max_val)
best_individual_history=[]
best_fitness_history=[]
for _ in range(generations):
new_population = []
for _ in range(pop_size):
parent1 = tournament_selection(population, tournament_size)
parent2 = tournament_selection(population, tournament_size)
child = crossover(parent1, parent2)
child = mutation(child, mutation_rate, min_val, max_val)
new_population.append(child)
population = new_population
best_individual = max(population, key=fitness)
best_fitness = fitness(best_individual)
best_individual_history.append(best_individual)
best_fitness_history.append(best_fitness)
return best_individual, best_fitness,best_individual_history,best_fitness_history
# 运行遗传算法
best_individual, best_fitness,best_individual_history,best_fitness_history = genetic_algorithm(pop_size, generations, tournament_size, mutation_rate, min_val, max_val)
print(f"最优解 x = {best_individual},最大值 f(x) = {best_fitness}")
print('best_individual_history=',best_individual_history)
print('best_fitness_history=',best_fitness_history)
plt.suptitle('遗传算法', y=0.95) # 设置图像名称
plt.subplot(1,3,1)
x = np.linspace(min_val , max_val, 1000)
y = target_function(x)
plt.plot(x, y, label='目标函数')
frame = len(best_individual_history)
x1 = best_individual_history[:frame + 1]
y1 = best_fitness_history[:frame + 1]
plt.scatter(x1, y1, c='b', label='最佳子代解与最佳适应度')
best_x=best_individual
best_y=best_fitness
plt.scatter(best_x, best_y, c='r',marker='^', label='最佳适应度')
plt.legend(loc='upper left')
plt.subplot(1,3,2)
frame = len(best_individual_history)
x1 = best_individual_history[:frame + 1]
y1 = best_fitness_history[:frame + 1]
plt.scatter(x1, y1, c='b', label='最佳子代解与最佳适应度')
plt.legend()
plt.subplot(1,3,3)
Calculation_numbers = np.arange(1, generations + 1)
plt.plot(Calculation_numbers, best_fitness_history, c='r',marker='o',label='计算次数-适应度')
plt.xlabel('计算次数')
plt.ylabel('适应度')
plt.legend()
#plt.tight_layout()
plt.savefig('ycsf1.png')
plt.show()
如果想看动画,代码修改为:
import random #引入random模块
import matplotlib.pyplot as plt #引入matplotlib模块
import numpy as np #引入numpy模块
import matplotlib.animation as animation
# 设置 matplotlib 支持中文
plt.rcParams['font.family'] = 'SimHei'
# 解决负号显示问题
plt.rcParams['axes.unicode_minus'] = False
# 参数设置
pop_size = 50 # 种群大小
generations = 100 # 迭代次数
tournament_size = 5 # 锦标赛选择的参赛个体数量
mutation_rate = 0.1 # 变异概率
min_val = 0 # 变量的最小值
max_val = 10 # 变量的最大值
#绘制目标函数图
#定义自变量
#x=np.linspace(min_val,max_val,1000)
#定义因变量
#y=- (x - 2) ** 2 + 10
#绘图
#plt.plot(x,y)
#plt.show()
# 目标函数
def target_function(x):
#return - (x - 2) ** 2 + 10
return x ** 2 * np.sin(5 * x) + 0.1 * x ** 2
# 初始化种群
def initialize_population(pop_size, min_val, max_val):
return [random.uniform(min_val, max_val) for _ in range(pop_size)]
# 计算适应度
def fitness(individual):
return target_function(individual)
# 选择操作(锦标赛选择)
def tournament_selection(population, tournament_size):
tournament = random.sample(population, tournament_size)
return max(tournament, key=fitness)
# 交叉操作(简单算术交叉)
def crossover(parent1, parent2):
alpha = random.random()
child = alpha * parent1 + (1 - alpha) * parent2
return child
# 变异操作
def mutation(individual, mutation_rate, min_val, max_val):
if random.random() < mutation_rate:
# 简单的变异,在一定范围内随机扰动
individual += random.uniform(-1, 1)
# 确保变异后的个体在合法区间内
individual = max(min_val, min(individual, max_val))
return individual
# 遗传算法主函数
def genetic_algorithm(pop_size, generations, tournament_size, mutation_rate, min_val, max_val):
population = initialize_population(pop_size, min_val, max_val)
best_individual_history=[]
best_fitness_history=[]
for _ in range(generations):
new_population = []
for _ in range(pop_size):
parent1 = tournament_selection(population, tournament_size)
parent2 = tournament_selection(population, tournament_size)
child = crossover(parent1, parent2)
child = mutation(child, mutation_rate, min_val, max_val)
new_population.append(child)
population = new_population
best_individual = max(population, key=fitness)
best_fitness = fitness(best_individual)
best_individual_history.append(best_individual)
best_fitness_history.append(best_fitness)
#best_individual = max(population, key=fitness)
#best_fitness = fitness(best_individual)
#best_individual_history.append(best_individual)
#best_fitness_history.append(best_fitness)
return best_individual, best_fitness,best_individual_history,best_fitness_history
# 运行遗传算法
best_individual, best_fitness,best_individual_history,best_fitness_history = genetic_algorithm(pop_size, generations, tournament_size, mutation_rate, min_val, max_val)
print(f"最优解 x = {best_individual},最大值 f(x) = {best_fitness}")
print('best_individual_history=',best_individual_history)
print('best_fitness_history=',best_fitness_history)
fig, ax = plt.subplots() # 定义要画图
ax.set_title('遗传算法') # 设置图像名称
scatter=ax.scatter([],[],c='b',label='最优子代与最优适应度关系')
ax.set_xlim(min_val - 1, max_val + 1)
#ax.set_ylim(min(best_fitness_history) - 1, max(best_fitness_history) + 1)
x=np.linspace(min_val-0.1,max_val+0.1,1000)
y=target_function(x)
ax.plot(x,y,label='目标函数')
ax.scatter(best_individual, best_fitness,c='r',label='最佳适应度')
frame = len(best_individual_history)
ax.legend()
def update(frame):
x = best_individual_history[:frame + 1]
y = best_fitness_history[:frame + 1]
scatter.set_offsets(np.c_[x, y])
return scatter,
ani=animation.FuncAnimation(fig, update, repeat=True,
frames=frame, interval=50)
plt.show()
运行代码获得的动画为:
图5 遗传算法运算过程动画
由于算的比较准,所以动画不是很明显,为此就稍微修改自变量的取值范围:
ax.set_xlim(min(best_individual_history) - 1, max(best_individual_history) + 1)
这样可以让动画显示的区域更明显:
图6 遗传算法运算过程动画放大
此时的完整代码为:
import random #引入random模块
import matplotlib.pyplot as plt #引入matplotlib模块
import numpy as np #引入numpy模块
import matplotlib.animation as animation
# 设置 matplotlib 支持中文
plt.rcParams['font.family'] = 'SimHei'
# 解决负号显示问题
plt.rcParams['axes.unicode_minus'] = False
# 参数设置
pop_size = 50 # 种群大小
generations = 100 # 迭代次数
tournament_size = 5 # 锦标赛选择的参赛个体数量
mutation_rate = 0.1 # 变异概率
min_val = 0 # 变量的最小值
max_val = 10 # 变量的最大值
#绘制目标函数图
#定义自变量
#x=np.linspace(min_val,max_val,1000)
#定义因变量
#y=- (x - 2) ** 2 + 10
#绘图
#plt.plot(x,y)
#plt.show()
# 目标函数
def target_function(x):
#return - (x - 2) ** 2 + 10
return x ** 2 * np.sin(5 * x) + 0.1 * x ** 2
# 初始化种群
def initialize_population(pop_size, min_val, max_val):
return [random.uniform(min_val, max_val) for _ in range(pop_size)]
# 计算适应度
def fitness(individual):
return target_function(individual)
# 选择操作(锦标赛选择)
def tournament_selection(population, tournament_size):
tournament = random.sample(population, tournament_size)
return max(tournament, key=fitness)
# 交叉操作(简单算术交叉)
def crossover(parent1, parent2):
alpha = random.random()
child = alpha * parent1 + (1 - alpha) * parent2
return child
# 变异操作
def mutation(individual, mutation_rate, min_val, max_val):
if random.random() < mutation_rate:
# 简单的变异,在一定范围内随机扰动
individual += random.uniform(-1, 1)
# 确保变异后的个体在合法区间内
individual = max(min_val, min(individual, max_val))
return individual
# 遗传算法主函数
def genetic_algorithm(pop_size, generations, tournament_size, mutation_rate, min_val, max_val):
population = initialize_population(pop_size, min_val, max_val)
best_individual_history=[]
best_fitness_history=[]
for _ in range(generations):
new_population = []
for _ in range(pop_size):
parent1 = tournament_selection(population, tournament_size)
parent2 = tournament_selection(population, tournament_size)
child = crossover(parent1, parent2)
child = mutation(child, mutation_rate, min_val, max_val)
new_population.append(child)
population = new_population
best_individual = max(population, key=fitness)
best_fitness = fitness(best_individual)
best_individual_history.append(best_individual)
best_fitness_history.append(best_fitness)
#best_individual = max(population, key=fitness)
#best_fitness = fitness(best_individual)
#best_individual_history.append(best_individual)
#best_fitness_history.append(best_fitness)
return best_individual, best_fitness,best_individual_history,best_fitness_history
# 运行遗传算法
best_individual, best_fitness,best_individual_history,best_fitness_history = genetic_algorithm(pop_size, generations, tournament_size, mutation_rate, min_val, max_val)
print(f"最优解 x = {best_individual},最大值 f(x) = {best_fitness}")
print('best_individual_history=',best_individual_history)
print('best_fitness_history=',best_fitness_history)
fig, ax = plt.subplots() # 定义要画图
ax.set_title('遗传算法') # 设置图像名称
scatter=ax.scatter([],[],c='b',label='最优子代与最优适应度关系')
#ax.set_xlim(min_val - 1, max_val + 1)
ax.set_xlim(min(best_individual_history) - 1, max(best_individual_history) + 1)
#ax.set_ylim(min(best_fitness_history) - 1, max(best_fitness_history) + 1)
x=np.linspace(min_val-0.1,max_val+0.1,1000)
y=target_function(x)
ax.plot(x,y,label='目标函数')
ax.scatter(best_individual, best_fitness,c='r',label='最佳适应度')
frame = len(best_individual_history)
ax.legend()
def update(frame):
x = best_individual_history[:frame + 1]
y = best_fitness_history[:frame + 1]
scatter.set_offsets(np.c_[x, y])
return scatter,
ani=animation.FuncAnimation(fig, update, repeat=True,
frames=frame, interval=50)
ani.save('ycsf.gif')
plt.show()
由以上方法可见,遗传算法虽然过程复杂,但计算比较准确。
【6】总结
学习了遗传算法的原理,掌握了使用python应用遗传算法求解简单方程的技巧。