当前位置: 首页 > article >正文

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应用遗传算法求解简单方程的技巧。


http://www.kler.cn/a/560995.html

相关文章:

  • 注意力机制在 Transformer 模型中的核心作用剖析
  • Docker下的Elastic search
  • 无前端经验如何快速搭建游戏站:使用 windsurf 从零到上线的详细指南
  • 机器学习数学基础:34.点二列
  • Vue3中watchEffect、watchPostEffect、watchSyncEffect的区别
  • 在LangFlow中集成OpenAI Compatible API类型的大语言模型
  • DeepSeek开源周高能开场:新一代高效推理引擎FlashMLA正式发布
  • EX_25/2/22
  • 115 道 MySQL 面试题,从简单到深入!
  • 《一起打怪兽吧》——自制一款Python小游戏
  • 基于Spring Boot的健康医院门诊在线挂号系统设与实现(LW+源码+讲解)
  • 超详细:数据库的基本架构
  • HandBrake for Mac v1.9.2 视频压缩及格式转换 汉化版 支持M、Intel芯片
  • TLS与自签名证书的创建、作用、用到的工具等知识的介绍
  • 反向代理模块kfj
  • 实操解决Navicat连接postgresql时出现‘datlastsysoid does not exist‘报错的问题
  • escape SQL中用法
  • 力扣-贪心-135 分发糖果
  • 如何加固织梦CMS安全,防webshell、防篡改、防劫持,提升DedeCMS漏洞防护能力
  • 将Ubuntu操作系统的安装源设置为阿里云