目录

1. 关于遗传算法

2. 遗传算法的步骤

3. 代码实现

3.1 工具函数

3.1.1 目标函数

3.1.2 解码

3.1.3 交叉

3.1.4 变异

3.2 主函数部分

3.3 代码

4. 其他


1. 关于遗传算法

遗传算法是根据生物进化论提出的计算最优解的一种算法,核心思想是物竞天择,适者生存

网上关于遗传算法的讲解很多,本章会利用python实现遗传算法实现计算函数最大值,将其中的细节进行讨论

本章利用的函数为:y = x^2 ,定义域为0-10

关于遗传算法利用的其实是基因的遗传重组,所以这里每一个基因都是二进制的序列,例如10101

那二进制映射回定义域就是解码过程, start + (end - start) * tmp / (pow(2,length)-1) ,start 是定义域的左值,end 是定义域的右值,tmp是二进制序列,length 是二进制序列的长度。通过这样的计算就可以将二进制映射回给定的定义域中

那么二进制序列的长度如何定义?

是根据计算精度而言的,例如这里要计算的精度为0.01。那么就需要0.01->0.02->...->10.00中间共有10*10^2 = 1000个数字,那么需要的二进制就是10,因为2^10 = 1024可以保存1000个数字。那么二进制的序列长度就是 10

2. 遗传算法的步骤

接下来看看遗传算法的步骤:

这里只是根据自己实现的代码进行步骤分析,有些细节或者和网上实现不同的地方会在最后补充

1. 初始化种群 : 因为产生的二进制序列一般来说不是一个,这样是为了下面更好的交叉操作。并且,多个二进制序列也有利于找到最优的解

2. 解码 : 解码的意思就是将产生的二进制序列映射到对应的定义域当中,因为二进制产生的值很大,例如上述例子,定义域在0-10,精度为0.01,那么二进制长度为10,如果不进行映射的话,随便的一个二进制都会超过定义域10

当解码完成后,初始化种群已经全部变成在定义域当中的随机n(产生二进制序列的个数)个点

3. 计算适应度 :将定义域中的随机解码的点进行计算,例子中的y = x^2 被称为适应度函数

计算适应度其实就是计算这些值(x)对应的y,比如要求取最大值,那么看一下随机产生的x,哪一个y大,然后对较大的进行操作。这样反复操作的话,就可以找到最大值

4. 轮盘赌选取父系存活概率 : 当随机产生的n个点,计算完适应度函数后,会生成对应的n个函数值。函数值越大,我们说他越好(我们要计算最大值),那么他应该存活的概率就大。对应的方法是轮盘赌,例如产生的y值: 2 和 9,那么2/(2+9) 和 9/(2+9) 就是2和9存活的概率,这种就是轮盘赌。

注意:这只是概率,不是绝对的 9 > 2 ,就一定是 9 存活

5. 交叉 : 交叉就是根据父系的二进制,将随机的比特位进行交换的操作,这样遗传的思维就出现了。

6. 变异 : 变异是为了跳出极值,将子代的二进制编码,随机取反。0- >1,1->0

具体的实现方式在代码里面讲解

3. 代码实现

如图,本章遗传算法实现的是计算y = x^2 的最大值

关于遗传算法的定义在这:

其中,mutation_rate 是二进制序列变异的概率,这个不应该过大,要不然子代就完全和父代不一样,那么遗传算法也就失去了意义

parents_rate 是父代中保存的概率,例如这里总共有10个种群,0.3就会保存3个父代,这里保存的方式是通过轮盘赌实现

实现的效果为:

3.1 工具函数

为了代码的模块化,这里utils里面存放了四个函数

3.1.1 目标函数

也就是适应度函数

# 目标函数
def function(x):# y = np.sin(x) * np.exp(-x)y = x**2return y

3.1.2 解码

decode 是根据传递的二进制序列矩阵bit_matrix(n*m,n是种群个数,m是二进制的长度) 进行编码,产生n个在start-end定义域中的十进制自变量

# 将二进制编码为十进制,并映射到定义域中
def decode(bit_matrix,num_group,start,end,length):ret = np.zeros(num_group)temp = []       # 保存转换的十进制数for i in range(num_group):tmp = int(''.join(map(lambda x:str(x),bit_matrix[i])),2)    # 获得每一条染色体的十进制ret[i] = start + (end - start) * tmp / (pow(2,length)-1)        # 映射回原始的定义域temp.append(tmp)return temp,ret

3.1.3 交叉

这里实现的方法有所不同

本章实现的遗传算法,种群数目是固定的 ,也就是说初始化是10个,那么父代保留了3个后,交叉产生的子代就只有7个,也就是代码中的count变量。

parents_groups 是父代的所有种群,而非保留之后的3个

实现交叉的方式为,将两组随机的二进制序列进行交叉。最后返回

# 交叉繁殖
def cross(count,parents_groups,length,cross_num=2):childen = []                        # 子代while len(childen) != count:       # 保证子代的数量和父代一样index = np.random.choice(np.arange(length),cross_num,replace=False)   # 随机交换cross_num个基因male = parents_groups[np.random.randint(0,len(parents_groups+1))]       # 从父代中随机挑选两个交叉繁殖female = parents_groups[np.random.randint(0,len(parents_groups+1))]childen_one = male.copy()childen_two = female.copy()childen_one[index] = female[index]          # 交换父母双方的基因产生两个子代childen.append(childen_one)if len(childen) == count:breakchilden_two[index] = male[index]childen.append(childen_two)return np.array(childen)

3.1.4 变异

变异是为了种群能够产生突变,这样随机产生的新的子代也许能够跳出极值

实现方式也很简单,num_mutation可以控制二进制变异的个数

# 变异
def mutation(children,mutation_rate,length,num_mutation=1):children_mutation = []for i in range(len(children)):tmp = children[i]if np.random.random() < mutation_rate:index = np.random.choice(np.arange(length),num_mutation,replace=False)for j in range(num_mutation):       # 变异if tmp[index[j]] == 1:tmp[index[j]] = 0else:tmp[index[j]]= 1children_mutation.append(tmp)return np.array(children_mutation)

3.2 主函数部分

有几点需要注意,计算适应度的时候,将它进行下面的操作,要不然轮盘赌选择的时候会报错。因为概率不能为负值

3.3 代码

主函数部分:

import numpy as np
import matplotlib.pyplot as plt
from utils import decode,function,cross,mutation# 设定超参数
start,end = 0,10
length = 10                     # 染色体长度 bit,精度
num_group = 10                  # 种群数量
iteration_time = 2000             # 迭代次数
mutation_rate = 0.1             # 变异率
parents_rate = 0.3              # 父代中的保存个数(概率)# 初始化二进制种群
init_group = np.random.randint(0,2,size=(num_group,length))parents_group = init_group      # 父代# 迭代
decode_parents_group = 0
for i in range(iteration_time):# 将二进制种群转为十进制,并映射到定义域中_, decode_parents_group = decode(bit_matrix=parents_group, num_group=num_group, start=start, end=end, length=length)# 计算种群适应度f = function(decode_parents_group)f = (f - np.min(f))+1e-8     # 防止 f 为负值或 0select = np.random.choice(np.arange(num_group),int(num_group*parents_rate),replace=True,p=f/sum(f))best_parents_group = parents_group[select]       # 父代中的保留count = len(parents_group) - len(best_parents_group)     # 计算差值# 交叉繁殖children = cross(count=count, parents_groups=parents_group, length=length)children = np.concatenate((best_parents_group, children))# 变异children = mutation(children=children,mutation_rate=mutation_rate,length=length)parents_group = childrenfun = function(decode_parents_group)
x = np.linspace(start,end,100)
plt.plot(x,function(x),color='r')
plt.scatter(decode_parents_group,function(decode_parents_group))
plt.title('max is :%.4f' % np.max(fun))
plt.show()

utils 部分:

import numpy as np# 目标函数
def function(x):# y = np.sin(x) * np.exp(-x)y = x**2return y# 将二进制编码为十进制,并映射到定义域中
def decode(bit_matrix,num_group,start,end,length):ret = np.zeros(num_group)temp = []       # 保存转换的十进制数for i in range(num_group):tmp = int(''.join(map(lambda x:str(x),bit_matrix[i])),2)    # 获得每一条染色体的十进制ret[i] = start + (end - start) * tmp / (pow(2,length)-1)        # 映射回原始的定义域temp.append(tmp)return temp,ret# 交叉繁殖
def cross(count,parents_groups,length,cross_num=2):childen = []                        # 子代while len(childen) != count:       # 保证子代的数量和父代一样index = np.random.choice(np.arange(length),cross_num,replace=False)   # 随机交换cross_num个基因male = parents_groups[np.random.randint(0,len(parents_groups+1))]       # 从父代中随机挑选两个交叉繁殖female = parents_groups[np.random.randint(0,len(parents_groups+1))]childen_one = male.copy()childen_two = female.copy()childen_one[index] = female[index]          # 交换父母双方的基因产生两个子代childen.append(childen_one)if len(childen) == count:breakchilden_two[index] = male[index]childen.append(childen_two)return np.array(childen)# 变异
def mutation(children,mutation_rate,length,num_mutation=1):children_mutation = []for i in range(len(children)):tmp = children[i]if np.random.random() < mutation_rate:index = np.random.choice(np.arange(length),num_mutation,replace=False)for j in range(num_mutation):       # 变异if tmp[index[j]] == 1:tmp[index[j]] = 0else:tmp[index[j]]= 1children_mutation.append(tmp)return np.array(children_mutation)

4. 其他

这里用很多地方和网上实现的不一致,还有一些地方自己也不是特别明白

例如,保留父代的时候,可以重复保留吗?

本章的方法是可以(改为False就可以不重复),这里个人认为,如果选择保留父代不重复的话,那么基本上保留的父代就是按照概率值从大到小进行保留,那么初始化不太好的时候,很容易掉入极值的坑里

    select = np.random.choice(np.arange(num_group),int(num_group*parents_rate),replace=True,p=f/sum(f))

其他的例如,如果变异率或者变异的个数过多的话,那么父代留给子代的信息就完全被破坏了,那么遗传的意义也就没有了

这里计算 y = np.sin(x) * np.exp(-x) 的结果为:

遗传算法求取函数最值问题相关推荐

  1. 遗传算法之求取函数极值

    遗传算法之求取函数极值 1.前言 在智能控制(刘金琨)这本里面讲了遗传算法求取函数极值的方法,这里给出一些个人理解时的注释,顺带 求解了第10章的课后习题第二题. 遗传算法流程图如下: 2.原书案例 ...

  2. python多元函数求极小值_使用遗传算法求二元函数的最小值

    二元函数为y=x1^2+x2^2,x∈[-5,5] NIND=121; %初始种群的个数(Number of individuals) NVAR=2; %一个染色体(个体)有多少基因 PRECI=20 ...

  3. python多元函数求解_使用遗传算法求二元函数的最小值

    二元函数为y=x1^2+x2^2,x∈[-5,5] NIND=121; %初始种群的个数(Number of individuals) NVAR=2; %一个染色体(个体)有多少基因 PRECI=20 ...

  4. 遗传算法求二元函数极值怎么编码_使用遗传算法求二元函数的最小值

    二元函数为y=x1^2+x2^2,x∈[-5,5] NIND=121; %初始种群的个数(Number of individuals) NVAR=2; %一个染色体(个体)有多少基因 PRECI=20 ...

  5. 遗传算法求三元函数极值(python)-采用实数编码

    遗传算法求三元函数极值(python)-采用实数编码 想看二进制编码编码的博客地址在这 遗传算法求三元函数极值(python)-采用二进制编码 本文的遗传算法采用实数编码求三元函数极值 所求函数为 ` ...

  6. 遗传算法求三元函数极值(python)-采用二进制编码

    想看实数编码编码的 博客地址遗传算法求三元函数极值(python)-采用实数编码 * 遗传算法求三元函数极值(python)-采用二进制编码 本文的遗传算法采用二进制编码求三元函数极值 所求函数为 要 ...

  7. 7:C语言之求分段函数的值

    #include <stdio.h>//定义main函数 int main() {//请在此添加'求分段函数的值'的代码/*****************Begin*********** ...

  8. MATLAB利用遗传算法求取最优解

    MATLAB内置GA函数,用以求解全局最优化问题,适用于求解目标函数最优解问题. 一.GA函数原型: 二.函数介绍 常用的两种分别是: 1.X = ga(fitnessfcn,nvars) 2.X = ...

  9. 遗传算法实现寻找函数最值

    遗传算法的原理参考维基百科:https://zh.wikipedia.org/wiki/%E9%81%97%E4%BC%A0%E7%AE%97%E6%B3%95 遗传算法流程图: 遗传算法的思想和流程 ...

最新文章

  1. apex英雄机器人探路者怎么玩_《Apex英雄》探路者机器人怎么玩 探路者机器人技能特性及玩法...
  2. java调用c库实例
  3. 36个创意广告海报欣赏
  4. 徐教授的对于商业模式创新的讲座!十分有用!
  5. python3 用pygame 简单建一个飞船模型
  6. mysql ICP优化的原理
  7. Linux运维工程师:30道面试题整理
  8. 【windows8开发】C++开发WinRT组件和JS调用
  9. jquery:validate的例子{转载}
  10. 联手微软,Docker公司将推出Docker Desktop for WSL 2
  11. 基于Spring的应用程序-迁移到Junit 5
  12. urllib常用小记
  13. 关于Relay Log无法自动删除的问题
  14. win32以动态链接库导出类及其成员变量
  15. debian编译openjdk8
  16. 吉米多维奇数学分析习题集学习指引
  17. android多个app音量调节问题,「App 音量控制」依每个 App 的使用需求自动调整音量(Android)...
  18. ClientToScreen 和ScreenToClient
  19. USACO3.4 “破锣摇滚”乐队 Raucous Rockers - DP
  20. 操作系统-进程甘特图画法

热门文章

  1. jsDelivr的CDN加速被污染
  2. 清华师姐网盘大曝光(整整400集python学习资料,真香)
  3. MySQL数据库 高级命令的使用与讲解
  4. 全国大学生智能车竞赛大四专门组别
  5. 浅谈电气火灾监控系统在煤矿高层公寓中的应用分析
  6. 计算机系统实验:二进制炸弹+缓冲区炸弹 (自我学习笔记)
  7. ubuntu16中英文输入法切换快捷键
  8. Java开发规范之代码格式篇(上)
  9. BLAST Database error: No alias or index file found for protein database [uniprot_sprot.fasta] in
  10. IT项目管理痛点和应对方法总结