Genetic Algorithm遗传算法学习

2023-10-18 06:59

本文主要是介绍Genetic Algorithm遗传算法学习,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

参考资料:http://blog.csdn.net/b2b160/article/details/4680853/#comments(冒昧的用了链接下的几张图)
百度百科:http://baike.baidu.com/link?url=FcwTBx_yPcD5DDEnN1FqvTkG4QNllkB7Yis6qFOL65wpn6EdT5LXFxUCmv4JlUfV3LUPHQGdYbGj8kHVs3GuaK

算法介绍

遗传算法是模拟达尔文生物进化论的自然选择和遗传学进化机理的计算模型。运用到了生物学中“适者生存,优胜劣汰”的原理。在每一次的进化过程中,把拥有更好环境适应性的基因传给下一代,直到最后的个体满足特定的条件,代表进化的结束,GA(后面都以GA代称为遗传算法的意思)算法是一种利用生物进化理论来搜索最优解的一种算法。

算法原理

算法的基本框架

了解算法的基本框架是理解整个算法的基础,算法的框架包含编码、适应度函数、初始群体的选择。先假设本例子的目标函数如下,求出他的最大值

f(x) = x1 * x1 + x2 * x2; 1<= x1 <=7,1<= x2<=7

1、适应度函数。适应度函数是用来计算个体的适应值计算,顾名思义,适应值越高的个体,环境适应性越好,自然就要有更多的机会把自己的基因传给下一代,所以,其实适应度函数在这里起着一个过滤条件的作用。在本例子,目标函数总为非负值,并且以函数最大化为优化目标,所以可以将函数的值作为适应值。

2、编码。编码指的是将个体的信息表示成编码的字符串形式。如果个体变量时数字的形式,可以转为二进制的方式。

算法的群体选择过程

这个过程是遗传算法的核心过程,在里面分为了3个小的步骤,选择,交叉,变异。

1、初始个体的选择过程。就是挑选哪些个体作为即将产生下一代的个体呢。过程如下:

(1).利用适值函数,计算每个个体的适值,计算每个个体的适值占总和的百分比。

(2).根据百分比为每个个体划定一定的所属区间。

(3).产生一个[0, 1]的小数,判断这个小数点落在哪个个体的区间内,就表明要选出这个个体。这里其实就已经蕴含着把高适值的个体优先传入下一代,因为适值高,有更高的几率小数是落在自己的区间内的。

用图示范的形式表现如下:


2、交叉运算。个体的交叉运算过程的步骤细节如下:

(1).首先对于上个选择步骤选择来的个体进行随机的两两配对。

(2).取出其中配对的一对个体,随机设定一个交叉点,2个个体的编码的交叉点后的编码值进行对调,生成新的2个个体编码。

(3).所有的配对的个体都执行步骤(2)操作,最后加入到一个结果集合中。

交叉运算的方式又很多,上面用的方法是其中比较常用的单点交叉方式。

用图示范的形式表现如下:


3.变异运算。变异运算过程的步骤细节如下:

(1).遍历从交叉运算所得结果的结果集,取出集中一个个体编码,准备做变异操作

(2).产生随机的一个变异点位置。所选个体的变异点位置的值做变异操作,将他的值取为反向的值。

(3).将所有的交叉运算所得的结果集中的元素都执行步骤(2)操作。

用图示范的形式如下:


整个遗传算法的原理过程,用一个流程图的表现形式如下:


算法代码实现

算法代码的测试用例正如算法原理所举的一样,遗传进化的阈值条件为:个体中产生了使目标函数最大化值的个体,就是基因为111111。

GATool.java:

[java] view plain copy print ?
  1. packageGA;
  2. importjava.util.ArrayList;
  3. importjava.util.Random;
  4. /**
  5. *遗传算法工具类
  6. *
  7. *@authorlyq
  8. *
  9. */
  10. publicclassGATool{
  11. //变量最小值
  12. privateintminNum;
  13. //变量最大值
  14. privateintmaxNum;
  15. //单个变量的编码位数
  16. privateintcodeNum;
  17. //初始种群的数量
  18. privateintinitSetsNum;
  19. //随机数生成器
  20. privateRandomrandom;
  21. //初始群体
  22. privateArrayList<int[]>initSets;
  23. publicGATool(intminNum,intmaxNum,intinitSetsNum){
  24. this.minNum=minNum;
  25. this.maxNum=maxNum;
  26. this.initSetsNum=initSetsNum;
  27. this.random=newRandom();
  28. produceInitSets();
  29. }
  30. /**
  31. *产生初始化群体
  32. */
  33. privatevoidproduceInitSets(){
  34. this.codeNum=0;
  35. intnum=maxNum;
  36. int[]array;
  37. initSets=newArrayList<>();
  38. //确定编码位数
  39. while(num!=0){
  40. codeNum++;
  41. num/=2;
  42. }
  43. for(inti=0;i<initSetsNum;i++){
  44. array=produceInitCode();
  45. initSets.add(array);
  46. }
  47. }
  48. /**
  49. *产生初始个体的编码
  50. *
  51. *@return
  52. */
  53. privateint[]produceInitCode(){
  54. intnum=0;
  55. intnum2=0;
  56. int[]tempArray;
  57. int[]array1;
  58. int[]array2;
  59. tempArray=newint[2*codeNum];
  60. array1=newint[codeNum];
  61. array2=newint[codeNum];
  62. num=0;
  63. while(num<minNum||num>maxNum){
  64. num=random.nextInt(maxNum)+1;
  65. }
  66. numToBinaryArray(array1,num);
  67. while(num2<minNum||num2>maxNum){
  68. num2=random.nextInt(maxNum)+1;
  69. }
  70. numToBinaryArray(array2,num2);
  71. //组成总的编码
  72. for(inti=0,k=0;i<tempArray.length;i++,k++){
  73. if(k<codeNum){
  74. tempArray[i]=array1[k];
  75. }else{
  76. tempArray[i]=array2[k-codeNum];
  77. }
  78. }
  79. returntempArray;
  80. }
  81. /**
  82. *选择操作,把适值较高的个体优先遗传到下一代
  83. *
  84. *@paraminitCodes
  85. *初始个体编码
  86. *@return
  87. */
  88. privateArrayList<int[]>selectOperate(ArrayList<int[]>initCodes){
  89. doublerandomNum=0;
  90. doublesumAdaptiveValue=0;
  91. ArrayList<int[]>resultCodes=newArrayList<>();
  92. double[]adaptiveValue=newdouble[initSetsNum];
  93. for(inti=0;i<initSetsNum;i++){
  94. adaptiveValue[i]=calCodeAdaptiveValue(initCodes.get(i));
  95. sumAdaptiveValue+=adaptiveValue[i];
  96. }
  97. //转成概率的形式,做归一化操作
  98. for(inti=0;i<initSetsNum;i++){
  99. adaptiveValue[i]=adaptiveValue[i]/sumAdaptiveValue;
  100. }
  101. for(inti=0;i<initSetsNum;i++){
  102. randomNum=random.nextInt(100)+1;
  103. randomNum=randomNum/100;
  104. sumAdaptiveValue=0;
  105. //确定区间
  106. for(intj=0;j<initSetsNum;j++){
  107. if(randomNum>sumAdaptiveValue
  108. &&randomNum<=sumAdaptiveValue+adaptiveValue[j]){
  109. //采用拷贝的方式避免引用重复
  110. resultCodes.add(initCodes.get(j).clone());
  111. break;
  112. }else{
  113. sumAdaptiveValue+=adaptiveValue[j];
  114. }
  115. }
  116. }
  117. returnresultCodes;
  118. }
  119. /**
  120. *交叉运算
  121. *
  122. *@paramselectedCodes
  123. *上步骤的选择后的编码
  124. *@return
  125. */
  126. privateArrayList<int[]>crossOperate(ArrayList<int[]>selectedCodes){
  127. intrandomNum=0;
  128. //交叉点
  129. intcrossPoint=0;
  130. ArrayList<int[]>resultCodes=newArrayList<>();
  131. //随机编码队列,进行随机交叉配对
  132. ArrayList<int[]>randomCodeSeqs=newArrayList<>();
  133. //进行随机排序
  134. while(selectedCodes.size()>0){
  135. randomNum=random.nextInt(selectedCodes.size());
  136. randomCodeSeqs.add(selectedCodes.get(randomNum));
  137. selectedCodes.remove(randomNum);
  138. }
  139. inttemp=0;
  140. int[]array1;
  141. int[]array2;
  142. //进行两两交叉运算
  143. for(inti=1;i<randomCodeSeqs.size();i++){
  144. if(i%2==1){
  145. array1=randomCodeSeqs.get(i-1);
  146. array2=randomCodeSeqs.get(i);
  147. crossPoint=random.nextInt(2*codeNum-1)+1;
  148. //进行交叉点位置后的编码调换
  149. for(intj=0;j<2*codeNum;j++){
  150. if(j>=crossPoint){
  151. temp=array1[j];
  152. array1[j]=array2[j];
  153. array2[j]=temp;
  154. }
  155. }
  156. //加入到交叉运算结果中
  157. resultCodes.add(array1);
  158. resultCodes.add(array2);
  159. }
  160. }
  161. returnresultCodes;
  162. }
  163. /**
  164. *变异操作
  165. *
  166. *@paramcrossCodes
  167. *交叉运算后的结果
  168. *@return
  169. */
  170. privateArrayList<int[]>variationOperate(ArrayList<int[]>crossCodes){
  171. //变异点
  172. intvariationPoint=0;
  173. ArrayList<int[]>resultCodes=newArrayList<>();
  174. for(int[]array:crossCodes){
  175. variationPoint=random.nextInt(codeNum*2);
  176. for(inti=0;i<array.length;i++){
  177. //变异点进行变异
  178. if(i==variationPoint){
  179. array[i]=(array[i]==0?1:0);
  180. break;
  181. }
  182. }
  183. resultCodes.add(array);
  184. }
  185. returnresultCodes;
  186. }
  187. /**
  188. *数字转为二进制形式
  189. *
  190. *@parambinaryArray
  191. *转化后的二进制数组形式
  192. *@paramnum
  193. *待转化数字
  194. */
  195. privatevoidnumToBinaryArray(int[]binaryArray,intnum){
  196. intindex=0;
  197. inttemp=0;
  198. while(num!=0){
  199. binaryArray[index]=num%2;
  200. index++;
  201. num/=2;
  202. }
  203. //进行数组前和尾部的调换
  204. for(inti=0;i<binaryArray.length/2;i++){
  205. temp=binaryArray[i];
  206. binaryArray[i]=binaryArray[binaryArray.length-1-i];
  207. binaryArray[binaryArray.length-1-i]=temp;
  208. }
  209. }
  210. /**
  211. *二进制数组转化为数字
  212. *
  213. *@parambinaryArray
  214. *待转化二进制数组
  215. */
  216. privateintbinaryArrayToNum(int[]binaryArray){
  217. intresult=0;
  218. for(inti=binaryArray.length-1,k=0;i>=0;i--,k++){
  219. if(binaryArray[i]==1){
  220. result+=Math.pow(2,k);
  221. }
  222. }
  223. returnresult;
  224. }
  225. /**
  226. *计算个体编码的适值
  227. *
  228. *@paramcodeArray
  229. */
  230. privateintcalCodeAdaptiveValue(int[]codeArray){
  231. intresult=0;
  232. intx1=0;
  233. intx2=0;
  234. int[]array1=newint[codeNum];
  235. int[]array2=newint[codeNum];
  236. for(inti=0,k=0;i<codeArray.length;i++,k++){
  237. if(k<codeNum){
  238. array1[k]=codeArray[i];
  239. }else{
  240. array2[k-codeNum]=codeArray[i];
  241. }
  242. }
  243. //进行适值的叠加
  244. x1=binaryArrayToNum(array1);
  245. x2=binaryArrayToNum(array2);
  246. result=x1*x1+x2*x2;
  247. returnresult;
  248. }
  249. /**
  250. *进行遗传算法计算
  251. */
  252. publicvoidgeneticCal(){
  253. //最大适值
  254. intmaxFitness;
  255. //迭代遗传次数
  256. intloopCount=0;
  257. booleancanExit=false;
  258. ArrayList<int[]>initCodes;
  259. ArrayList<int[]>selectedCodes;
  260. ArrayList<int[]>crossedCodes;
  261. ArrayList<int[]>variationCodes;
  262. int[]maxCode=newint[2*codeNum];
  263. //计算最大适值
  264. for(inti=0;i<2*codeNum;i++){
  265. maxCode[i]=1;
  266. }
  267. maxFitness=calCodeAdaptiveValue(maxCode);
  268. initCodes=initSets;
  269. while(true){
  270. for(int[]array:initCodes){
  271. //遗传迭代的终止条件为存在编码达到最大适值
  272. if(maxFitness==calCodeAdaptiveValue(array)){
  273. canExit=true;
  274. break;
  275. }
  276. }
  277. if(canExit){
  278. break;
  279. }
  280. selectedCodes=selectOperate(initCodes);
  281. crossedCodes=crossOperate(selectedCodes);
  282. variationCodes=variationOperate(crossedCodes);
  283. initCodes=variationCodes;
  284. loopCount++;
  285. }
  286. System.out.println("总共遗传进化了"+loopCount+"次");
  287. printFinalCodes(initCodes);
  288. }
  289. /**
  290. *输出最后的编码集
  291. *
  292. *@paramfinalCodes
  293. *最后的结果编码
  294. */
  295. privatevoidprintFinalCodes(ArrayList<int[]>finalCodes){
  296. intj=0;
  297. for(int[]array:finalCodes){
  298. System.out.print("个体"+(j+1)+":");
  299. for(inti=0;i<array.length;i++){
  300. System.out.print(array[i]);
  301. }
  302. System.out.println();
  303. j++;
  304. }
  305. }
  306. }
算法调用类Client.java:

[java] view plain copy print ?
  1. packageGA;
  2. /**
  3. *Genetic遗传算法测试类
  4. *@authorlyq
  5. *
  6. */
  7. publicclassClient{
  8. publicstaticvoidmain(String[]args){
  9. //变量最小值和最大值
  10. intminNum=1;
  11. intmaxNum=7;
  12. //初始群体规模
  13. intinitSetsNum=4;
  14. GATooltool=newGATool(minNum,maxNum,initSetsNum);
  15. tool.geneticCal();
  16. }
  17. }
算法多次测试的输出结果:

测试1:

[java] view plain copy print ?
  1. 总共遗传进化了0
  2. 个体1:111001
  3. 个体2:101010
  4. 个体3:101110
  5. 个体4:111111
测试2:

[java] view plain copy print ?
  1. 总共遗传进化了1
  2. 个体1:101101
  3. 个体2:111111
  4. 个体3:100111
  5. 个体4:100111
测试3:

[java] view plain copy print ?
  1. 总共遗传进化了14
  2. 个体1:110101
  3. 个体2:111111
  4. 个体3:110101
  5. 个体4:110011

算法结果分析

可以看到,遗传进化的循环次数还是存在着不确定定性的,原因在于测试的个体数太少,如果个体数比较多的话,几轮就可以出现111111这样的个体编码组了。从结果可以看出,总的还是能够向1多的方向发展的。

说说我对遗传算法的理解

通过实现了GA算法,觉得这有点集成算法的味道,因为这其实用到了跨学科的知识,用生物进化理论的知识,去作为一个搜索最优解的解决方案,而且算法本身理解和实现也不是特别的难。

这篇关于Genetic Algorithm遗传算法学习的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/230968

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

【机器学习】高斯过程的基本概念和应用领域以及在python中的实例

引言 高斯过程(Gaussian Process,简称GP)是一种概率模型,用于描述一组随机变量的联合概率分布,其中任何一个有限维度的子集都具有高斯分布 文章目录 引言一、高斯过程1.1 基本定义1.1.1 随机过程1.1.2 高斯分布 1.2 高斯过程的特性1.2.1 联合高斯性1.2.2 均值函数1.2.3 协方差函数(或核函数) 1.3 核函数1.4 高斯过程回归(Gauss

【学习笔记】 陈强-机器学习-Python-Ch15 人工神经网络(1)sklearn

系列文章目录 监督学习:参数方法 【学习笔记】 陈强-机器学习-Python-Ch4 线性回归 【学习笔记】 陈强-机器学习-Python-Ch5 逻辑回归 【课后题练习】 陈强-机器学习-Python-Ch5 逻辑回归(SAheart.csv) 【学习笔记】 陈强-机器学习-Python-Ch6 多项逻辑回归 【学习笔记 及 课后题练习】 陈强-机器学习-Python-Ch7 判别分析 【学

系统架构师考试学习笔记第三篇——架构设计高级知识(20)通信系统架构设计理论与实践

本章知识考点:         第20课时主要学习通信系统架构设计的理论和工作中的实践。根据新版考试大纲,本课时知识点会涉及案例分析题(25分),而在历年考试中,案例题对该部分内容的考查并不多,虽在综合知识选择题目中经常考查,但分值也不高。本课时内容侧重于对知识点的记忆和理解,按照以往的出题规律,通信系统架构设计基础知识点多来源于教材内的基础网络设备、网络架构和教材外最新时事热点技术。本课时知识

线性代数|机器学习-P36在图中找聚类

文章目录 1. 常见图结构2. 谱聚类 感觉后面几节课的内容跨越太大,需要补充太多的知识点,教授讲得内容跨越较大,一般一节课的内容是书本上的一章节内容,所以看视频比较吃力,需要先预习课本内容后才能够很好的理解教授讲解的知识点。 1. 常见图结构 假设我们有如下图结构: Adjacency Matrix:行和列表示的是节点的位置,A[i,j]表示的第 i 个节点和第 j 个

Node.js学习记录(二)

目录 一、express 1、初识express 2、安装express 3、创建并启动web服务器 4、监听 GET&POST 请求、响应内容给客户端 5、获取URL中携带的查询参数 6、获取URL中动态参数 7、静态资源托管 二、工具nodemon 三、express路由 1、express中路由 2、路由的匹配 3、路由模块化 4、路由模块添加前缀 四、中间件