遗传算法个人入门笔记

news/2025/1/19 21:41:26/文章来源:https://www.cnblogs.com/tomorin/p/18680249

先举一个简单的求解例子:

变量x,y

函数f(x,y) = (x-5)^2 + (y+3)^2 - 5

求最小值。

def test(x,y):return (x - 5)**2 + (y - 3)**2 - 5

显然,这个函数在x=5,y=3时取最小值-5。现在我们尝试用遗传算法解决之。

遗传算法主要是模拟生物进化的过程,将每一个值视作一个生物,有自己的DNA,会发生交叉变异,同时“适者生存”。

1.编码:

规定x,y的取值范围是[-10,10],并将其映射在一个长度为12的二进制列表中:

尽管严格来说,长度为12的二进制列表最大的值为2^12-1=4095。但为了化简逆映射的求解,我们视作4096,使之可被除尽。此时x,y的取值为[-10,10)。

区间长度是20,2^12 = 4096,20/4096 = 0.0048828125。可以知道二进制数每增长1,对应的10进制数大约增长0.0048828125。

写出其编码函数:

def encode(n,n_min,n_max,dna_length):n_range = n_max - n_minpies= n_range / 2**dna_lengthres = n - n_minn_bit = res / piesreturn get_bits_list(n_bit,dna_length)

2.解码函数:

def decode(dna,dna_length):result = 0for i in range(dna_length):result += dna[i] * (2**i)return result

将这些代码封装到一个类中:

class my_ga():def __init__(self,n_min,n_max,dna_length):self.n_min = n_minself.n_max = n_maxself.dna_length = dna_lengthself.n_range = self.n_max - self.n_minself.pies= self.n_range / 2**self.dna_lengthdef test(x,y):return (x - 5)**2 + (y - 3)**2 - 5def encode(self,n):res = n - self.n_minn_bit = res / self.piesprint(f"n_bit is {n_bit}")return self.get_bits_list(n_bit)def decode(self,dna):result = 0for i in range(self.dna_length):result += dna[i] * (2**i)print(f"result now is {result}")origin = result * self.pies + self.n_minreturn origin

3.种群:

交叉与变异是建立在种群的基础上的。我们将一个(x,y)的二进制条件下的数值对视为一个个体,它们组成一个种群。先将种群数设为1000,同时,定义一个计算适应性的函数。

    def get_adapt(self):adapt = np.zeros(shape=(1000))for i in range(1000):adapt[i] = -self.test(self.pop_dna[i])adapt_max = np.max(adapt)adapt_min = np.min(adapt)adapt_normal = (adapt-adapt_min)/(adapt_max-adapt_min) + 0.001return adapt_normal
        self.pop_dna = np.random.randint(2,size=(1000,2,dna_length))self.adapt_normal = self.get_adapt()

接着定义根据适应性选择个体的函数:

def select(self):idx = np.random.choice(np.arange(1000),size=(1000), replace=True, p=(self.adapt_normal)/(self.adapt_normal.sum()))return self.pop_dna[idx]

为了让算法更灵活,我们将1000换为pop_size。

4.交叉与变异:

交叉与变异并非是必然发生的,我们需要定义一个交叉率与变异率,同时定义交叉、变异函数:

    def cross(self,child):if np.random.rand() < self.cross_rate:mother = self.pop_dna[np.random.randint(self.pop_size)]for j in range(2):cross_point = np.random.randint(low=0, high=self.pop_size)child[j][cross_point:] = mother[j][cross_point:]return childdef muta(self,child):if np.random.rand() < self.muta_rate:muta_dna = np.random.randint(0,2)muta_point = np.random.randint(0,self.pop_size)child[muta_dna][muta_point] ^= 1return childdef cross_muta(self):new_pop = self.pop_dna.copy()for i in range(self.pop_size):new_pop[i] = self.cross(new_pop[i])new_pop[i] = self.muta(new_pop[i])return new_pop

输出函数:

def get_best(self):the_min = 1e9x = 0y = 0for i in range(self.pop_size):if the_min > self.test(self.pop_dna[i]):the_min = self.test(self.pop_dna[i])x = self.decode(self.pop_dna[i][0])y = self.decode(self.pop_dna[i][1])print(f"best indiv is ({x},{y}), result is {the_min}")

测试:

ga = my_ga(n_min=-10,n_max=10,dna_length=12,pop_size=1000,cross_rate=0.8,muta_rate=0.08)print(ga.pop_dna)
genration = 10for _ in range(genration):ga.cross_muta()ga.select()ga.get_adapt()ga.get_best()

完整、且标准的含注释代码:

import numpy as npclass GeneticAlgorithm:# 初始化方法,设置遗传算法的参数def __init__(self, n_min, n_max, dna_length, pop_size, cross_rate, muta_rate):self.n_min = n_min  # 最小范围self.n_max = n_max  # 最大范围self.dna_length = dna_length  # DNA长度self.pop_size = pop_size  # 种群大小self.cross_rate = cross_rate  # 交叉概率self.muta_rate = muta_rate  # 变异概率self.n_range = n_max - n_min  # 范围差值self.unit_interval = self.n_range / (2**dna_length)  # 每个DNA单元对应的实际数值范围self.population = np.random.randint(2, size=(pop_size, 2, dna_length))  # 随机初始化种群self.normalized_fitness = self.calculate_fitness()  # 初始化适应度# 目标函数,需要最小化的函数def objective_function(self, individual):x = self.decode(individual[0])  # 解码第一个DNA片段y = self.decode(individual[1])  # 解码第二个DNA片段return (x - 5)**2 + (y - 3)**2 - 5  # 计算适应度值# 将数值编码为二进制DNA片段def encode(self, n):res = n - self.n_min  # 转换为范围内的数值n_binary = res / self.unit_interval  # 转换为二进制数return self.to_binary_list(n_binary)# 将二进制DNA片段解码为数值def decode(self, dna):result = 0for i in range(self.dna_length):result += dna[i] * (2**i)decoded_value = result * self.unit_interval + self.n_minreturn decoded_value# 计算适应度值并进行归一化def calculate_fitness(self):fitness = np.zeros(shape=(self.pop_size))  # 初始化适应度数组for i in range(self.pop_size):fitness[i] = -self.objective_function(self.population[i])  # 计算适应度值max_fitness = np.max(fitness)min_fitness = np.min(fitness)normalized_fitness = (fitness - 0.001 - min_fitness) / (max_fitness - min_fitness) + 0.01self.normalized_fitness = normalized_fitnessreturn normalized_fitness# 选择适应度高的个体进行繁殖def select_population(self):indices = np.random.choice(np.arange(self.pop_size), size=(self.pop_size), replace=True, p=(self.normalized_fitness) / (self.normalized_fitness.sum()))self.population = self.population[indices]# 交叉操作,生成新个体def crossover(self, offspring):if np.random.rand() < self.cross_rate:parent = self.population[np.random.randint(self.pop_size)]for j in range(2):crossover_point = np.random.randint(low=0, high=self.dna_length)offspring[j][crossover_point:] = parent[j][crossover_point:]return offspring# 变异操作def mutate(self, offspring):if np.random.rand() < self.muta_rate:muta_dna = np.random.randint(0, 2)muta_point = np.random.randint(0, self.dna_length)offspring[muta_dna][muta_point] ^= 1return offspring# 对整个种群应用交叉和变异操作def apply_crossover_and_mutation(self):new_population = self.population.copy()for i in range(self.pop_size):new_population[i] = self.crossover(new_population[i])new_population[i] = self.mutate(new_population[i])return new_population# 获取当前种群中最优的个体def get_best_individual(self):best_fitness = float('inf')best_x, best_y = 0, 0for i in range(self.pop_size):current_fitness = self.objective_function(self.population[i])if best_fitness > current_fitness:best_fitness = current_fitnessbest_x = self.decode(self.population[i][0])best_y = self.decode(self.population[i][1])print(f"Best individual is ({best_x}, {best_y}), fitness is {best_fitness}")# 初始化遗传算法对象
ga = GeneticAlgorithm(n_min=-10, n_max=10, dna_length=16, pop_size=500, cross_rate=0.8, muta_rate=0.08)
generations = 10# 迭代执行遗传算法
for _ in range(generations):ga.apply_crossover_and_mutation()ga.select_population()ga.calculate_fitness()ga.get_best_individual()

输出如下:

自此入门成功......

下一篇:用遗传算法处理2024数学建模国赛C题(咕咕咕中......)

ps:由于这个函数过于简单,并没有体现进化的过程。但我懒得改了。

这是个更显著的代码:

import numpy as npclass GeneticAlgorithm:# 初始化方法,设置遗传算法的参数def __init__(self, n_min, n_max, dna_length, pop_size, cross_rate, muta_rate,dna_kind_size):self.n_min = n_min  # 最小范围self.n_max = n_max  # 最大范围self.dna_length = dna_length  # DNA长度self.pop_size = pop_size  # 种群大小self.cross_rate = cross_rate  # 交叉概率self.muta_rate = muta_rate  # 变异概率self.n_range = n_max - n_min  # 范围差值self.dna_kind_size = dna_kind_sizeself.unit_interval = self.n_range / (2**dna_length)  # 每个DNA单元对应的实际数值范围self.population = np.random.randint(0, dna_kind_size, size=(pop_size, dna_kind_size, dna_length))  # 随机初始化种群self.normalized_fitness = self.calculate_fitness()  # 初始化适应度# 目标函数,需要最小化的函数def objective_function(self, individual):x = self.decode(individual[0])  # 解码第一个DNA片段y = self.decode(individual[1])  # 解码第二个DNA片段z = self.decode(individual[2]) return -((x - 5)**2 + (y - 3)**2 + (z + 2)**2) + 5  # 计算适应度值# 将二进制DNA片段解码为数值def decode(self, dna):result = 0for i in range(self.dna_length):result += dna[i] * (2**i)decoded_value = result * self.unit_interval + self.n_minreturn decoded_value# 计算适应度值并进行归一化def calculate_fitness(self):fitness = np.zeros(shape=(self.pop_size))  # 初始化适应度数组for i in range(self.pop_size):fitness[i] = self.objective_function(self.population[i])  # 计算适应度值max_fitness = np.max(fitness)min_fitness = np.min(fitness)normalized_fitness = (fitness - min_fitness) / (max_fitness - min_fitness + 0.00001) + 0.001self.normalized_fitness = normalized_fitnessreturn normalized_fitness# 选择适应度高的个体进行繁殖def select_population(self):print("normallized_fitness_sum is ",self.normalized_fitness.sum())indices = np.random.choice(np.arange(self.pop_size), size=(self.pop_size), replace=True, p=(self.normalized_fitness) / (self.normalized_fitness.sum()))self.population = self.population[indices]# 交叉操作,生成新个体def crossover(self, offspring):if np.random.rand() < self.cross_rate:parent = self.population[np.random.randint(self.pop_size)]for j in range(self.dna_kind_size):crossover_point = np.random.randint(low=0, high=self.dna_length)offspring[j][crossover_point:] = parent[j][crossover_point:]return offspring# 变异操作def mutate(self, offspring):if np.random.rand() < self.muta_rate:muta_dna = np.random.randint(0, self.dna_kind_size)muta_point = np.random.randint(0, self.dna_length)offspring[muta_dna][muta_point] ^= 1return offspring# 对整个种群应用交叉和变异操作def apply_crossover_and_mutation(self):new_population = self.population.copy()for i in range(self.pop_size):new_population[i] = self.crossover(new_population[i])new_population[i] = self.mutate(new_population[i])return new_population# 获取当前种群中最优的个体def get_best_individual(self):best_fitness = float('inf')best_x, best_y,best_z = 0, 0, 0for i in range(self.pop_size):current_fitness = self.objective_function(self.population[i])if best_fitness > current_fitness:best_fitness = current_fitnessbest_x = self.decode(self.population[i][0])best_y = self.decode(self.population[i][1])best_z = self.decode(self.population[i][2])print(f"Best individual is ({best_x}, {best_y}, {best_z}), fitness is {best_fitness}")# 初始化遗传算法对象
ga = GeneticAlgorithm(n_min=-10, n_max=10, dna_length=16, pop_size=10000, cross_rate=0.8, muta_rate=0.08,dna_kind_size = 3)
generations = 50# 迭代执行遗传算法
for _ in range(generations):ga.apply_crossover_and_mutation()ga.select_population()ga.calculate_fitness()ga.get_best_individual()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/871871.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

excel快速定位到某一行

左上角输入框输入:A100定位到第100行

2024秋季学期 电子技术基础期末复习笔记

这期末也太难了吧,15*2,俩超级难的电路,直接给我算麻了电路分析模拟电路

【牛客训练记录】牛客周赛 Round 77

训练情况赛后反思 打一半吃饭去了,C题看到 ax+by=k 的问题,简单的扩欧exgcd没反应过来,简单数论还是不熟悉TAT,D题DSU计算联通块大小时 \(i\) 打成 \(a_i\) 疯狂 RE 被硬控了十几分钟 A题 输出题目所述的第几个字符串即可 #include <bits/stdc++.h> // #define int l…

LIS于LCS

LIS与LCS是动态规划中最常见的两种情况,LIS也就是最长上升子序列,而LCS是最长公共子序列。 在解决这个问题之前,先要明白为什么是序列,举个例子来说明,在数组 [1,2,3,4,5,6]中,[2,3,5]就是其子序列,也就是说,子序列其实就是数组中存在先后顺序,但不强调连续的子数组。…

层次分析法:数学建模

今天学习了层次分析法和数学建模,这里就简单写一下自己的学习新的,参考的资料是B站上的免费网课,老师讲的不错,可以去围观,学习,希望可以拿个奖。https://www.bilibili.com/video/BV1p14y1U7Nr/?spm_id_from=333.337.search-card.all.click 上面这里是链接。本文的大部分…

那些年我在 HL 集训做的题【某人别催了!】

某人别催了!!!Day 0 1.16 下午到 HL,居然还写了一道题? P8855 [POI2002] 商务旅行 LCA 板子。不理解当时为啥要写这个东东,可能是为了热热身吧。 Day 1 讲整体二分,但是没听懂。貌似是魔改版 CDQ...不管它。但是我似乎发现了一片新天地,一切的一切都从下面的一道题说起…

Mac 刷题环境配置

方便Mac 刷题,记录一些环境配置Mac 刷题环境配置 这篇博文主要记录自己为了更方便的在 Mac 上写算法题,主要是基于 Clion做的一些环境配置;有些操作其实在 Windows ,Linux 下也是通用的,如果看到的小伙伴也可以结合自己的情况参考。 Clion 插件 推荐一下这个插件 C/C++ Si…

excel对列数据去重(数据核对)

第一步,选中A列数据,单击功能区——数据选项卡——高级第二步,在弹出的对话框中,选中“将筛选结果复制到其他位置”,"列表区域"填写A列的地址:$A$1:$A$17,“复制到”填写:B1,把“选择不重复记录”勾上,确定即可。结果如下图

前端开发day1

day1 目的:开发一个平台(网站)- 前端开发:HTML、CSS、JavaScript- Web框架:接收请求并处理- MySQL数据库:存储数据地方快速上手:基于Flask Web框架让你快速搭建一个网站出来。深入学习:基于Django框架(主要)1,快速开发网站 pip install flaskfrom flask import Flask…

Centos7.9安装phpldapadmin

Centos7.9安装phpldapadmin@目录一、背景二、正文2.1 安装phpldapadmin2.4 登录phpldapadmin界面三、安装途中可能碰到的报错错误场景1:执行步骤“安装phpldapadmin”执行命令:yum install -y phpldapadmin时报错错误场景2:安装phpldapadmin完成后,apache启动报错,执行启动…

数据库密码安全修改:保护织梦网站账户安全的黄金法则

严格权限控制:仅授予最小化权限给真正需要访问数据库的人,避免不必要的暴露风险。定期清理过期账号,防止非法入侵。 日志记录完善:开启详细的日志记录功能,记录下每一次登录、退出、增删改查等关键事件。一旦发现问题可以迅速定位原因并采取相应措施。步骤 描述备份数据优…

为什么网站后台连接不了并报错?

当您发现网站后台无法连接并报错时,可能是由多种原因引起的。为了有效解决问题,我们需要从多个角度进行排查和优化。以下是详细的解决方案: 一、检查数据库连接数据库配置:确认数据库配置文件(如config.php)中的连接参数是否正确。 包括数据库主机名、端口、用户名、密码…