GA 算法

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

遗传算法(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

相关帖子

回帖

欢迎来到这里!

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

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

推荐标签 标签

  • Python

    Python 是一种面向对象、直译式电脑编程语言,具有近二十年的发展历史,成熟且稳定。它包含了一组完善而且容易理解的标准库,能够轻松完成很多常见的任务。它的语法简捷和清晰,尽量使用无异义的英语单词,与其它大多数程序设计语言使用大括号不一样,它使用缩进来定义语句块。

    556 引用 • 675 回帖
  • 支付宝

    支付宝是全球领先的独立第三方支付平台,致力于为广大用户提供安全快速的电子支付/网上支付/安全支付/手机支付体验,及转账收款/水电煤缴费/信用卡还款/AA 收款等生活服务应用。

    29 引用 • 347 回帖 • 1 关注
  • 链滴

    链滴是一个记录生活的地方。

    记录生活,连接点滴

    171 引用 • 3847 回帖
  • GitLab

    GitLab 是利用 Ruby 一个开源的版本管理系统,实现一个自托管的 Git 项目仓库,可通过 Web 界面操作公开或私有项目。

    46 引用 • 72 回帖
  • SMTP

    SMTP(Simple Mail Transfer Protocol)即简单邮件传输协议,它是一组用于由源地址到目的地址传送邮件的规则,由它来控制信件的中转方式。SMTP 协议属于 TCP/IP 协议簇,它帮助每台计算机在发送或中转信件时找到下一个目的地。

    4 引用 • 18 回帖 • 637 关注
  • Kubernetes

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

    116 引用 • 54 回帖 • 1 关注
  • Kotlin

    Kotlin 是一种在 Java 虚拟机上运行的静态类型编程语言,由 JetBrains 设计开发并开源。Kotlin 可以编译成 Java 字节码,也可以编译成 JavaScript,方便在没有 JVM 的设备上运行。在 Google I/O 2017 中,Google 宣布 Kotlin 成为 Android 官方开发语言。

    19 引用 • 33 回帖 • 78 关注
  • 链书

    链书(Chainbook)是 B3log 开源社区提供的区块链纸质书交易平台,通过 B3T 实现共享激励与价值链。可将你的闲置书籍上架到链书,我们共同构建这个全新的交易平台,让闲置书籍继续发挥它的价值。

    链书社

    链书目前已经下线,也许以后还有计划重制上线。

    14 引用 • 257 回帖
  • Ant-Design

    Ant Design 是服务于企业级产品的设计体系,基于确定和自然的设计价值观上的模块化解决方案,让设计者和开发者专注于更好的用户体验。

    17 引用 • 23 回帖
  • Android

    Android 是一种以 Linux 为基础的开放源码操作系统,主要使用于便携设备。2005 年由 Google 收购注资,并拉拢多家制造商组成开放手机联盟开发改良,逐渐扩展到到平板电脑及其他领域上。

    335 引用 • 324 回帖
  • IBM

    IBM(国际商业机器公司)或万国商业机器公司,简称 IBM(International Business Machines Corporation),总公司在纽约州阿蒙克市。1911 年托马斯·沃森创立于美国,是全球最大的信息技术和业务解决方案公司,拥有全球雇员 30 多万人,业务遍及 160 多个国家和地区。

    17 引用 • 53 回帖 • 146 关注
  • Spark

    Spark 是 UC Berkeley AMP lab 所开源的类 Hadoop MapReduce 的通用并行框架。Spark 拥有 Hadoop MapReduce 所具有的优点;但不同于 MapReduce 的是 Job 中间输出结果可以保存在内存中,从而不再需要读写 HDFS,因此 Spark 能更好地适用于数据挖掘与机器学习等需要迭代的 MapReduce 的算法。

    74 引用 • 46 回帖 • 569 关注
  • 区块链

    区块链是分布式数据存储、点对点传输、共识机制、加密算法等计算机技术的新型应用模式。所谓共识机制是区块链系统中实现不同节点之间建立信任、获取权益的数学算法 。

    92 引用 • 752 回帖
  • 笔记

    好记性不如烂笔头。

    310 引用 • 794 回帖
  • CentOS

    CentOS(Community Enterprise Operating System)是 Linux 发行版之一,它是来自于 Red Hat Enterprise Linux 依照开放源代码规定释出的源代码所编译而成。由于出自同样的源代码,因此有些要求高度稳定的服务器以 CentOS 替代商业版的 Red Hat Enterprise Linux 使用。两者的不同在于 CentOS 并不包含封闭源代码软件。

    239 引用 • 224 回帖
  • 房星科技

    房星网,我们不和没有钱的程序员谈理想,我们要让程序员又有理想又有钱。我们有雄厚的房地产行业线下资源,遍布昆明全城的 100 家门店、四千地产经纪人是我们坚实的后盾。

    6 引用 • 141 回帖 • 590 关注
  • GitHub

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

    210 引用 • 2040 回帖
  • 快应用

    快应用 是基于手机硬件平台的新型应用形态;标准是由主流手机厂商组成的快应用联盟联合制定;快应用标准的诞生将在研发接口、能力接入、开发者服务等层面建设标准平台;以平台化的生态模式对个人开发者和企业开发者全品类开放。

    15 引用 • 127 回帖 • 1 关注
  • 又拍云

    又拍云是国内领先的 CDN 服务提供商,国家工信部认证通过的“可信云”,乌云众测平台认证的“安全云”,为移动时代的创业者提供新一代的 CDN 加速服务。

    20 引用 • 37 回帖 • 573 关注
  • PHP

    PHP(Hypertext Preprocessor)是一种开源脚本语言。语法吸收了 C 语言、 Java 和 Perl 的特点,主要适用于 Web 开发领域,据说是世界上最好的编程语言。

    179 引用 • 408 回帖 • 488 关注
  • 酷鸟浏览器

    安全 · 稳定 · 快速
    为跨境从业人员提供专业的跨境浏览器

    3 引用 • 59 回帖 • 47 关注
  • Rust

    Rust 是一门赋予每个人构建可靠且高效软件能力的语言。Rust 由 Mozilla 开发,最早发布于 2014 年 9 月。

    58 引用 • 22 回帖 • 9 关注
  • Follow
    4 引用 • 12 回帖 • 9 关注
  • Mobi.css

    Mobi.css is a lightweight, flexible CSS framework that focus on mobile.

    1 引用 • 6 回帖 • 756 关注
  • Solo

    Solo 是一款小而美的开源博客系统,专为程序员设计。Solo 有着非常活跃的社区,可将文章作为帖子推送到社区,来自社区的回帖将作为博客评论进行联动(具体细节请浏览 B3log 构思 - 分布式社区网络)。

    这是一种全新的网络社区体验,让热爱记录和分享的你不再感到孤单!

    1441 引用 • 10068 回帖 • 494 关注
  • 七牛云

    七牛云是国内领先的企业级公有云服务商,致力于打造以数据为核心的场景化 PaaS 服务。围绕富媒体场景,七牛先后推出了对象存储,融合 CDN 加速,数据通用处理,内容反垃圾服务,以及直播云服务等。

    28 引用 • 226 回帖 • 134 关注
  • Electron

    Electron 基于 Chromium 和 Node.js,让你可以使用 HTML、CSS 和 JavaScript 构建应用。它是一个由 GitHub 及众多贡献者组成的活跃社区共同维护的开源项目,兼容 Mac、Windows 和 Linux,它构建的应用可在这三个操作系统上面运行。

    15 引用 • 136 回帖 • 3 关注