小白易懂的遗传算法(Python代码实现)_遗传算法python代码详解-程序员宅基地

技术标签: python  numpy  开发语言  

无约束的遗传算法(最简单的)

最开始真正理解遗传算法,是通过这个博主的讲解,安利给小白们看一看,遗传算法的Python实现(通俗易懂),我觉得博主写的让人特别容易理解,关键是代码也不报错,然后我就照着他的代码抄了一遍,认真地理解了一下每一个模块,:编码、解码、适应度函数写法、选择、交叉和变异的实现过程,下面也谈一谈我在整个过程中的认识,以及对代码的一种通俗解释:
1、编码:这里主要运用的就是一种二进制的编码,将要求解的问题的解,从十进制的自然数以某一种方式用二进制表达出来,每一个0或1作为是一个基因位,一个数的众多基因构成一条染色体,也就是一个个体,进而众多染色体构成一个种群,所说的种群规模其实就是这些染色体的个数,最后用这个种群去参与到遗传算法的各个过程中,并且二进制的编码对于交叉和变异的操作会简单一点。
2、解码:因为适应度函数是用十进制的自然数写的,所以在每一次迭代中,要把二进制的染色体,再变成十进制的数,才能参与到适应度的计算中,就照着解码公式写出来就好了。

##解码函数
def decode(pop):
   return   pop.dot(2 ** np.arange(DNA_SIZE)[::-1]) *(X_max-X_min)/ float(2**DNA_SIZE-1) +X_min

3、适应度函数:作为遗传变异的根据,这个函数通常跟我们目标函数有关系,因为后面在选择过程中,是保留适应度值更大的个体,所以适应度值我们都认为是越大越好,那么目标函数是求最大值的时候,那也就是说适应度值越大,越接近目标,所以令适应度函数=目标函数。
目标函数求最小值时,如果也想达到这样的效果,则令适应度函数=1/目标函数。
但是在这里又遇到了一个问题,因为适应度值必须是正的,因为要求占比,但目标函数值有可能是负的,所以就做了下面的这个转换,让求出来的适应度值是正的,并且与目标函数值的变化是一致的,如果以后遇到的话,也可以尝试着自己去想表达式来解决,只要明白这个目的。

"""求解的目标表达式为:
y = 10 * math.sin(5 * x) + 7 * math.cos(4 * x)
x=[0,5]
"""
def aim(x):
    return 10*np.sin(5*x)+7*np.cos(4*x)
##适应度计算函数
def fitnessget(pred):
    return pred + 1e-3 - np.min(pred)

4、选择:最常用的就是轮盘赌方式,了解完他的定义之后发现他的代码实现也不难,比如有五个个体的种群,索引序号是[0,1,2,3,4],那就是计算适应度值,并且求一下在总的适应度里面的占比,得到[0.1,0.2,0.3,0.1,0.3],然后根据这每一个个体的比例来随机抽数,得到[2,4,2,1,4],就比如两个0.3的概率最大,那么抽取到个体2和4的概率就更大,最终根据这个序号去选择种群中对应的个体,进行保留到下一代,这就实现了适应环境的留下,不适应的淘汰。

##自然选择函数(轮盘赌)
def select(pop, fitness):           
    # print(abs(fitness))
    # print(fitness.sum())
    idx = np.random.choice(np.arange(pop_size), size=pop_size, replace=True,p=fitness/fitness.sum())
    # print(idx)
    return pop[idx]

4、交叉:二进制的交叉就是针对每一个个体,随机找到一个个体,然后再随机找到某几个基因位,这两个个体的这些基因位进行交换,这里我看的时间比较久,实在不懂就打印出来看看是啥咯

def change(parent, pop):
    x = np.random.rand()
    print('x:{}'.format(x))
    if x < PC:    #交叉
        i_ = np.random.randint(0, pop_size, size=1)  ##随机找到要与之交叉的某一行,也就是某另一个个体
        print('i_:{}'.format(i_))
        cross_points = np.random.randint(0, 2, size=DNA_SIZE)##生成一个只有0和1的列表,长度等于基因长度
        print('cross_points:{}'.format(cross_points))
        cross_points = cross_points.astype(np.bool)  ##1的地方就是True
        print('cross_points:{}'.format(cross_points))
        print(np.where(cross_points==True))   ##np.where()就是找到True的地方,就是用这种方法来找到1的地方,作为交叉的基因位
        print('cross_points:{}'.format(cross_points))
        print('parent[cross_points]:{}'.format(parent[cross_points]))
        parent[cross_points] = pop[i_, cross_points]
        print('parent:{}'.format(parent))
    return parent

5、变异:二进制的变异就很简单了,就是选择基因位,然后0变成1,1变成0,代码也比较容易实现。

def variation(child,pm):                  #变异
    for point in range(DNA_SIZE):
        if np.random.rand() < pm:
            child[point] = 1 if child[point] == 0 else 0
    # print(child)
    return child

6、遗传算法主体

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

##定义全局变量
pop_size = 5  # 种群数量
PC=0.6 # 交叉概率
PM=0.01 #变异概率
X_max=5    #最大值
X_min=0     #最小值
DNA_SIZE=10  #DNA长度与保留位数有关,2**10 当前保留3位小数点,这个应该是二进制考虑的问题,保留的规则可以去搜一下,有的实际问题需要实数编码的话,就直接看着所要求的问题设置编码长度就好了
N_GENERATIONS=100    ##迭代次数

##生成初始解,这个初始种群就是一个可行解的集合,在这样的条件下进行选择、交叉和变异操作,选出最适应当前环境的个体,也就得到了我们的最优解
pop = np.random.randint(2, size=(pop_size, DNA_SIZE))   ###得到初始化种群
# print(pop)
X = np.arange(0,N_GENERATIONS,1)
Y = [None]*N_GENERATIONS   ##先产生一个全部都是0的列表,用于存放每一次迭代的最优值,最后进行画图展示迭代过程
for i in range(N_GENERATIONS):  ##上面写的选择、交叉、变异都是在一次进化中的操作,每一次迭代都要进行
    #解码
    # print(pop)
    X_value= decode(pop)
    
    #获取目标函数值
    F_values = aim(X_value)
    
    #获取适应值
    fitness = fitnessget(F_values)
    # print(fitness)
    if(i==0):
        max=np.max(F_values)
        max_DNA = pop[np.argmax(F_values), :]  ##取取得适应度最大值的那个个体
        
    if(max<np.max(F_values)):
        max=np.max(F_values)
        max_DNA=pop[np.argmax(F_values), :]
        
    if (i % 10 == 0):
        print("Most fitted value and X: \n",
              np.max(F_values), decode(pop[np.argmax(F_values), :]))
    #选择
    pop = select(pop,fitness)
    # print(pop)
    pop_copy = pop.copy()
    # print(pop_copy)
    for index,parent in enumerate(pop):
        # print(parent)
        child = change(parent,pop_copy)
        child = variation(child,PM)
        # print(child)
        pop[index] = child
    Y[i] = max
print("目标函数最大值为:",max)
print("其DNA值为:",max_DNA)
print("其X值为:",decode(max_DNA))
plt.plot(X,Y)

结果如下:
在这里插入图片描述

好了,大家把上面的代码和解释全部认真读一遍,小白也能懂遗传算法了。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_43697614/article/details/127541300

智能推荐

hook技术截取服务器信息,Windows Hook技术-程序员宅基地

文章浏览阅读532次。0x01 简介有人称它为“钩子”,有人称它为“挂钩”技术。谈到钩子,很容易让人联想到在钓东西,比如鱼钩就用于钓鱼。编程技术的钩子也是在等待捕获系统中的某个消息或者动作。钩子的应用范围非常广泛,比如输入监控、API拦截、消息捕获、改变程序执行流程等方面。杀毒软件会用Hook技术钩住一些API函数,比如钩住注册表读写函数,从而防止病毒对注册表进行写入;病毒使用Hook技术有针对性的捕获键盘的输入,从而..._windows通过hook获取新创建的进程

操作系统原理——实验五:内存管理_Debug_实验5内存管理-程序员宅基地

文章浏览阅读858次。操作系统原理——实验五:内存管理_Debug_实验5内存管理

《JavaScript百炼成仙》 全书知识点整理-程序员宅基地

文章浏览阅读1.3k次。i++}console.log(sum) // 5050补充:i++ 和 ++i 的理解i++ 是自增运算符,表示把当前的变量自增一个单位。(先运算、后自增)++i 是先自增一个单位,然后在运算。(先自增、后运算)不论是 i++ 还是 ++i ,只要执行完毕,i的值都是自增。for循环和while循环语法for循环:for(语句1; 语句2; 语句3){被执行的代码块}语句1:在循环(代码块)开始前执行语句2:定于运行循环(代码块)的条件语句3:在循环(代码块)已被执行_javascript百炼成仙

el-select 的rules详解_el-select rules-程序员宅基地

文章浏览阅读4.5k次。直接上代码 <el-form-item label="实体" prop="entityId"> <div class="block"> <el-select v-model="form.entityId" clearable placeholder="请选择" style="width: 60%"> <el-option v-for="item i_el-select rules

java计算机毕业设计口腔医院患者服务系统MyBatis+系统+LW文档+源码+调试部署-程序员宅基地

文章浏览阅读65次。java计算机毕业设计口腔医院患者服务系统MyBatis+系统+LW文档+源码+调试部署。jsp+sqlserver基于JSP的养老院老人日常生活管理系统。springboot基于B_S模式的后勤管理系统-在线报修系统。jsp基于信息理论联合聚类的协同过滤推荐算法研究与实现。ssm攀枝花市房屋租售信息管理平台的设计与实现。ssm基于SSM的英语学习网站的设计与实现。ssm基于Web前端开发技术的儿童教育网站。jsp“原创音乐爱好者”交流网站程序LW。ssm宠物喂养资讯分享平台的设计与实现。

微信公众号开发《发送消息模板到公众号(java版)》_java 微信 公众号 群发消息-程序员宅基地

文章浏览阅读5.4k次。具体实现过程工具类测试:(使用前需要适当修改即可) package com.shove.util;import java.io.InputStream; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.URL;import net.sf.json.JSONObject;public_java 微信 公众号 群发消息

随便推点

创新工场联合创始人汪华:2013年中国移动互联网进入深水区_知乎联合创始汪华简介-程序员宅基地

文章浏览阅读1.3k次。汪华:我记得从2009年,我们创新工场刚开始的时候,那一年开始,每年我大概都要到各个场合呼吁一下移动互联网。最早每年都说移动互联网这件事有多好,这个事明年、后年会怎么样。当时大家还是将信将疑,觉得这是一个什么东西。但是最近几年,我们当时关于移动互联网的预言都比较准确的实现了,从当时几百万,到现在已经5亿台设备。再往后看,10亿手机用户换成智能手机也是指日可待。我们当时做的公司只有几万用户,到几_知乎联合创始汪华简介

LIO-SAM源码解读(四):mapOptimization-程序员宅基地

文章浏览阅读1.3k次,点赞2次,收藏7次。写在前面功能简介:1.scan-to-map匹配:提取当前激光帧特征点(角点、平面点),局部关键帧map的特征点,执行scan-to-map迭代优化,更新当前帧位姿;2.关键帧因子图优化; 关键帧加入因子图,添加激光里程计因子、GPS因子、闭环因子、执行因子图优化,更新所有关键帧的位姿;3.闭环检测:在历史关键帧中找距离相近,时间相隔较远的帧设为匹配帧,匹配帧周围提取局部关键帧地图,同样执行scan-to-map匹配,得到位姿变换,构建闭环因子数据,加入因子图优化。订阅:1.订阅当前激光帧点云信

HDU 4333 Revolving Digits (exkmp)_4333nnncom-程序员宅基地

文章浏览阅读145次。题意给你一个数NNN大小为1010000010^{100000}10100000,之后你可以将这个数字的最后一位放到第一位其他位置顺次往后移动,现在问你,在移动的过程中有多少个数字大于NNN或者小于NNN,或者等于NNN.思路字符串特别大,所有显然要用字符串输入。首先我们将NNN翻一倍续到后面记为shshsh,这样的话,新的字符串就会包含字符串变换的所有情况。之后我们发现每次变换之后我们要和..._4333nnncom

mysql全表扫描会涉及到io吗_造成MySQL全表扫描的原因-程序员宅基地

文章浏览阅读265次。全表扫描是数据库搜寻表的每一条记录的过程,直到所有符合给定条件的记录返回为止。通常在数据库中,对无索引的表进行查询一般称为全表扫描;然而有时候我们即便添加了索引,但当我们的SQL语句写的不合理的时候也会造成全表扫描。以下是经常会造成全表扫描的SQL语句及应对措施:1. 使用null做为判断条件如:select account from member where nickname = null;建议..._为什么mysql 8.0的全索引扫描都走物理io

Cookie中特殊字符_cookie 特殊字符-程序员宅基地

文章浏览阅读934次。Tomcat中Cookie特殊字符话不多说,放码过来<% String date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()); Cookie cookie =new Cookie("date",date); response.addCookie(cookie);%>jsp页面中加入cookie来记录登录时间,并在下一次访问时获得上一次的登陆时间。<% Co_cookie 特殊字符

shell 编程_shell编程-程序员宅基地

文章浏览阅读1.5k次。shell 编程、流编辑(sed)、模式搜索与处理(awk)、自动化脚本部署实践_shell编程

推荐文章

热门文章

相关标签