GA 算法

本贴最后更新于 1597 天前,其中的信息可能已经沧海桑田

遗传算法(genetic algorithm)是模拟达尔文生物进化论的自然选择和遗传学机理的生物进化过程计算模型,是一种通过模拟自然进化过程搜索最优解的方法。下面我将分享自己在做GA模型的心得与困惑。

先来整理一下 GA 的基本步骤:

  1. 随机生成一定数量的种群。
  2. 对种群的个体进行编码与评估。
  3. 选用合适的方法对现有种群中的个体做出选择。
  4. 对选择出来的个体进行“交叉”并获得新的个体。
  5. 对下一代进行”突变“操作。

第一步:随机生成一定数量的种群。首先应该构思存储个体的数据结构。我选择的是嵌套的列表(list)。一个个体的形式为[[个体],[编码],评估值],一个种群则是[[[个体1],[编码1],评估值1],[[个体2] ,[编码2],评估值2],[[个体3],[编码3],评估值3],...]。采用随机的方式生成种群/个体:

''' popnum:单位种群中个体数量,cistern:存储单个种群的数据池,lbound,ubound:个体的取值范围 precision:取值的精度,n:问题的维度 ''' def initpop(): cistern=[] for i in range(popnum): particle=[] for j in range(n): particle.append(round(random.uniform(lbound,ubound),precision)) cistern.append([particle,[],None]) return cistern

第二步:选择合适的编码方案以及评估函数。我采用的是经典的二进制编码形式,这样的编码有个好处是可以利用 Python 自带的 bin()函数快速实现,但是一般情况下各个维度的数字是需要编在一起的,而 bin()函数不能保证二进制数值的长度,往往导致在转化较小数字的时候其二进制长度过短,即便是将多个维度编码后的二进制数值简单拼接,我们也需要在拼接处设置标志位,这样才能在“交叉”过后将各维度分开,如果不设标志位而随机分割,那么将会在一定层面上导致“二次交叉”或“自我交叉”,这样便失去了“交叉”的意义,为了解决这一问题我们可以采用 format()函数,也可以对各个维度分别编码,分别“交叉”,在这里我选择后者。对于评估函数,我采用问题本身,即目标函数的函数值。

def D2B(num): #编码(十进制2二进制) return bin(round((num-lbound)*(pow(2,l)-1)/(ubound-lbound))) def B2D(num): #解码(二进制2十进制) return round(lbound+(ubound-lbound)/(pow(2,l)-1)*int(num,2),2) def trans(cistern): #对种群进行二进制编码 for i in cistern: for j in range(n): i[1].append(D2B(i[0][j])) return cistern def fitness(cistern): #对种群进行评估 for i in cistern: i[2]=fit(i[0]) return cistern

第三步:选用合适的方法对现有种群中的个体做出选择。个体选择的方法有很多,轮盘赌、 锦标赛选择、排名选择,等。在这里我选择最为简单的轮盘赌。由于函数对于种群池的修改是直接地 所以我将采用“一夫一妻制”,即三个父代个体不能产生两个子代个体,这也是为了避免多余“交叉”。

def select(cistern): reservoir=[] choice=[] resualt={} s=0 for i in cistern: #将种群中所有的适应值相加 s=s+i[2] for j in cistern: #求每个个体的占比 reservoir.append(j[2]/s) for k in range(1,popnum): #求每个个体的累计占比 reservoir[k]=reservoir[k]+reservoir[k-1] reservoir.insert(0,0) #补充轮盘的开端,设为0 for c in range(popnum): #选择次数为种群容量 r=random.random() #选择概率 for t in range(1,len(reservoir)-1): if r<reservoir[t] and r>reservoir[t-1]: choice.append(t-1) for d in set(choice): #采用字典的方式存储各个个体以及被选中的次数 resualt[d]=choice.count(d) resualt=sorted(resualt.items(), key=lambda item: item[1],reverse=True) #以被选中的次数大小排序 choice=[] for u in resualt: choice.append(u[0]) return choice #返回选择的结果(下标)

第四步:对选择出来的个体进行“交叉”并获得新的个体。这一步地操作,我采用对原种群直接修改的方式。 对于两个个体的编码,选择一个交叉点位并将交叉点位以及其后面的二进制位一并交换,而且也采用前面提到的分别“交叉”。

def crossover(a,b): #染色体(个体)单位 ch=random.random() #交叉概率 if ch<overchance: length=9999999 for i in a[1]+b[1]: #对较小长度的二进制选择交叉位作为各个维度的交叉位 if len(i)<length: length=len(i) r=random.randint(2,length-1) #选择交叉位 for j in range(n): #对二进制数值进行剪切和拼接 temp=a[1][j][r:] a[1][j]=a[1][j][:r]+b[1][j][r:] b[1][j]=b[1][j][:r]+temp a[0][j]=B2D(a[1][j]) #更改十进制数值 b[0][j]=B2D(b[1][j]) a[2]=fit(a[0]) #重新评估函数 b[2]=fit(b[0])

第五步:对下一代进行”突变“操作。“突变”是此算法中比较简单的流程,一般采用单点变异。

def variation(cistern): for i in cistern: c=random.random() #变异概率 if c<variantchance: #达成条件进行变异 m=99999 for x in i[1]: #以长度较小的二进制值选择点位 if len(x)<m: m=len(x) r=random.randint(2,m-1) #变异点位 for j in range(n): #更换点位的值 if i[1][j][r]=='0': i[1][j]=replace_char(i[1][j],'1',r) i[0][j]=B2D(i[1][j]) else: i[1][j]=replace_char(i[1][j],'0',r) i[0][j]=B2D(i[1][j]) i[2]=fit(i[0]) #重新评估函数 return cistern

最后进行一下总结,第一步以树的结构存储种群中的个体,第二部采用分别编码,第三步采用“一夫一妻制”选择 并且优先选择被选中次数多的个体进行下一步的操作,第四步采用分别“交叉”,第五步简单变异。剩下还有一些特殊的函数 匹配函数,保持最优函数,目标函数和字符交叉函数。

def replace_char(string,char,index): #单字符交叉,用于“变异” string=list(string) string[index]=char return ''.join(string) def fit(x): #目标函数,函数值即为适应度。 value=round(10*math.sin(5*x[0])+7*abs(x[1]-5)+10,precision) return value def match(choice): #匹配函数,防止选选择的个体个数为奇数。 if len(choice)%2!=0: choice.pop() return choice def best(cistern,Best): #最优个体保持函数 tem=sorted(cistern,key=lambda x:x[2],reverse=True)[0] if not Best: Best=copy.deepcopy(tem) elif tem[2]>Best[2]: Best=copy.deepcopy(tem) return Best

接下来以上面代码的目标函数对 GA 进行测试:

import math import random import copy popnum=50 ubound=10 lbound=-10 precision=3 l=0 while pow(2,l)<(ubound-lbound)/(1/pow(10,precision)): #计算所需二进制长度 l=l+1 n=2 #2-D overchance=0.8 variantchance=0.3 Best=[] a=initpop() trans(a) fitness(a) for j in range(100): s=select(a) if s: c=match(s) for i in range(0,len(c),2): crossover(a[c[i]],a[c[i+1]]) variation(a) Best=best(a,Best) print(Best)

QQ 截图 20200329203944.pngQQ 截图 20200329204003.png

相关帖子

回帖

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...

推荐标签 标签

  • 一些有用的避坑指南。

    69 引用 • 93 回帖
  • 外包

    有空闲时间是接外包好呢还是学习好呢?

    26 引用 • 233 回帖 • 1 关注
  • 锤子科技

    锤子科技(Smartisan)成立于 2012 年 5 月,是一家制造移动互联网终端设备的公司,公司的使命是用完美主义的工匠精神,打造用户体验一流的数码消费类产品(智能手机为主),改善人们的生活质量。

    4 引用 • 31 回帖
  • WiFiDog

    WiFiDog 是一套开源的无线热点认证管理工具,主要功能包括:位置相关的内容递送;用户认证和授权;集中式网络监控。

    1 引用 • 7 回帖 • 612 关注
  • CongSec

    本标签主要用于分享网络空间安全专业的学习笔记

    1 引用 • 1 回帖 • 39 关注
  • 钉钉

    钉钉,专为中国企业打造的免费沟通协同多端平台, 阿里巴巴出品。

    15 引用 • 67 回帖 • 260 关注
  • GraphQL

    GraphQL 是一个用于 API 的查询语言,是一个使用基于类型系统来执行查询的服务端运行时(类型系统由你的数据定义)。GraphQL 并没有和任何特定数据库或者存储引擎绑定,而是依靠你现有的代码和数据支撑。

    4 引用 • 3 回帖 • 4 关注
  • 周末

    星期六到星期天晚,实行五天工作制后,指每周的最后两天。再过几年可能就是三天了。

    14 引用 • 297 回帖
  • TGIF

    Thank God It's Friday! 感谢老天,总算到星期五啦!

    291 引用 • 4495 回帖 • 664 关注
  • Swagger

    Swagger 是一款非常流行的 API 开发工具,它遵循 OpenAPI Specification(这是一种通用的、和编程语言无关的 API 描述规范)。Swagger 贯穿整个 API 生命周期,如 API 的设计、编写文档、测试和部署。

    26 引用 • 35 回帖 • 2 关注
  • OkHttp

    OkHttp 是一款 HTTP & HTTP/2 客户端库,专为 Android 和 Java 应用打造。

    16 引用 • 6 回帖 • 88 关注
  • RYMCU

    RYMCU 致力于打造一个即严谨又活泼、专业又不失有趣,为数百万人服务的开源嵌入式知识学习交流平台。

    4 引用 • 6 回帖 • 62 关注
  • 大疆创新

    深圳市大疆创新科技有限公司(DJI-Innovations,简称 DJI),成立于 2006 年,是全球领先的无人飞行器控制系统及无人机解决方案的研发和生产商,客户遍布全球 100 多个国家。通过持续的创新,大疆致力于为无人机工业、行业用户以及专业航拍应用提供性能最强、体验最佳的革命性智能飞控产品和解决方案。

    2 引用 • 14 回帖
  • GitHub

    GitHub 于 2008 年上线,目前,除了 Git 代码仓库托管及基本的 Web 管理界面以外,还提供了订阅、讨论组、文本渲染、在线文件编辑器、协作图谱(报表)、代码片段分享(Gist)等功能。正因为这些功能所提供的便利,又经过长期的积累,GitHub 的用户活跃度很高,在开源世界里享有深远的声望,并形成了社交化编程文化(Social Coding)。

    209 引用 • 2040 回帖
  • Bug

    Bug 本意是指臭虫、缺陷、损坏、犯贫、窃听器、小虫等。现在人们把在程序中一些缺陷或问题统称为 bug(漏洞)。

    76 引用 • 1742 回帖 • 2 关注
  • OpenResty

    OpenResty 是一个基于 NGINX 与 Lua 的高性能 Web 平台,其内部集成了大量精良的 Lua 库、第三方模块以及大多数的依赖项。用于方便地搭建能够处理超高并发、扩展性极高的动态 Web 应用、Web 服务和动态网关。

    17 引用 • 51 关注
  • Dubbo

    Dubbo 是一个分布式服务框架,致力于提供高性能和透明化的 RPC 远程服务调用方案,是 [阿里巴巴] SOA 服务化治理方案的核心框架,每天为 2,000+ 个服务提供 3,000,000,000+ 次访问量支持,并被广泛应用于阿里巴巴集团的各成员站点。

    60 引用 • 82 回帖 • 617 关注
  • 开源

    Open Source, Open Mind, Open Sight, Open Future!

    415 引用 • 3598 回帖
  • NetBeans

    NetBeans 是一个始于 1997 年的 Xelfi 计划,本身是捷克布拉格查理大学的数学及物理学院的学生计划。此计划延伸而成立了一家公司进而发展这个商用版本的 NetBeans IDE,直到 1999 年 Sun 买下此公司。Sun 于次年(2000 年)六月将 NetBeans IDE 开源,直到现在 NetBeans 的社群依然持续增长。

    78 引用 • 102 回帖 • 712 关注
  • Kubernetes

    Kubernetes 是 Google 开源的一个容器编排引擎,它支持自动化部署、大规模可伸缩、应用容器化管理。

    118 引用 • 54 回帖 • 5 关注
  • 友情链接

    确认过眼神后的灵魂连接,站在链在!

    24 引用 • 373 回帖
  • DNSPod

    DNSPod 建立于 2006 年 3 月份,是一款免费智能 DNS 产品。 DNSPod 可以为同时有电信、网通、教育网服务器的网站提供智能的解析,让电信用户访问电信的服务器,网通的用户访问网通的服务器,教育网的用户访问教育网的服务器,达到互联互通的效果。

    6 引用 • 26 回帖 • 528 关注
  • OneNote
    1 引用 • 3 回帖
  • 微软

    微软是一家美国跨国科技公司,也是世界 PC 软件开发的先导,由比尔·盖茨与保罗·艾伦创办于 1975 年,公司总部设立在华盛顿州的雷德蒙德(Redmond,邻近西雅图)。以研发、制造、授权和提供广泛的电脑软件服务业务为主。

    8 引用 • 44 回帖
  • 阿里云

    阿里云是阿里巴巴集团旗下公司,是全球领先的云计算及人工智能科技公司。提供云服务器、云数据库、云安全等云计算服务,以及大数据、人工智能服务、精准定制基于场景的行业解决方案。

    85 引用 • 324 回帖
  • 脑图

    脑图又叫思维导图,是表达发散性思维的有效图形思维工具 ,它简单却又很有效,是一种实用性的思维工具。

    32 引用 • 100 回帖
  • 负能量

    上帝为你关上了一扇门,然后就去睡觉了....努力不一定能成功,但不努力一定很轻松 (° ー °〃)

    89 引用 • 1251 回帖 • 391 关注