Python 遗传算法实现字符串

流程

1. 初始化

2. 适应度函数

3. 选择

4. 交叉

5. 变异

适应度函数计算方法

计算个体间的差:分别计算每个元素与目标元素的差取平方和

种群:计算总体均值

操作 说明
编码方式 ASCII码
种群规模 5000
初始种群的个体取值范围 !!!!!!!!!!!!!!!!!!
(33,33,33,33,33,33,33,33,33
,33,33,33,33,33,33,33,33,33)
~
``````````````````
(126,126,126,126,126,126,126,126,126,
126,126,126,126,126,126,126,126,126)
选择操作 个体选择概率
分配策略 根据概率保留对应个数
个体选择方法 锦标赛选择方法
交叉概率 0.7
交叉方式 多点交叉
变异方式 随机多点突变
最大迭代步数 500

效果图

小结

  • 一开始我设计的选择方法是把低于平均的个体淘汰,但是这样操作会导致陷入局部最优,循环500次依旧没有结果,很难找到最优个体。后面仔细看书,用书上的锦标赛算法,提高了随机性,可以找到了目标序列。

  • 根据流程,我发现经过几轮的遗传,种群规模会迅速下降,因为中间补充的个体数量无法抵消淘汰的个体数量。于是我根据种群规模设计了阶梯式的概率,以便可以维持种群规模。

  • 对于上面的问题,我开始想在选择后立即补充

    即 y=100/7+0.05x(x为选择后剩余的种群数量),但是补充的内容无法实现最后的功能:1.补充随机新个体,这就和选择前的操作无异,种群适应度没有太大变化。2.补充选择后的个体,会导致陷入局部最优,种群发展速度慢。3.综合 1 2 补充,

    依旧没有明显效果。

  • 书上的最优概率,(主要是突变的概率非常低)对于产生新个体的速度较慢,基因重组的效果感觉不够明显,很容易陷入局部最优和陷入一个死局面,需要许久才能跳出这个局面

  • 后面我自己修改了概率,依旧有这种问题,目前还没解决。

  • 这次的代码写的比较不合理,高耦合。有许多地方可以改进,避免大量重复循环,以提高程序执行效率

补充

  • 关于补充选择淘汰的个体,我发现可以在cross,即基因重组中改变他后代产生的children个数,直到恢复到设置的种群规模。在基因突变部分,不再是往种群中添加新的个体,而是修改现有种群的基因。
  1. #coding=utf-8
  2. import numpy as np
  3. import matplotlib as mpl
  4. import matplotlib.pyplot as plt
  5. import random
  6. best = [72, 101, 108, 108, 111, 44, 105,99,106,98,64,102,111,120,109,97,105,108]
  7. #最佳序列
  8. def get_ran(b=33,e=126):
  9. """
  10. 获取随机字符值,默认从可显示字符开始(33-126)
  11. """
  12. return random.randint(b,e)
  13. def get_pos(cou=17):
  14. """
  15. 获取随机位置,默认到17
  16. """
  17. return random.randint(0,cou)
  18. class Chromosome:
  19. """
  20. 染色体类
  21. """
  22. def __init__(self,dna=None):
  23. """
  24. 初始化,可指定DNA序列顺序,默认DNA为随机序列。
  25. """
  26. if dna is not None:
  27. self.dna = dna[:]
  28. else :
  29. self.dna = []
  30. for i in range(18):
  31. self.dna.append(get_ran())
  32. def to_asc(self):
  33. """
  34. 将DNA序列由int转为str
  35. """
  36. str = ''
  37. for chrx in self.dna:
  38. str = str + chr(chrx)
  39. return str
  40. def __str__(self):
  41. """
  42. 将DNA序列由int转为str
  43. """
  44. str = ''
  45. for chrx in self.dna:
  46. str = str + chr(chrx)
  47. return str
  48. def mutation(self,which=-1):
  49. """
  50. 变异操作,默认产生随机个变异位点,突变为随机值,可指定突变位置
  51. """
  52. if which == -1 :
  53. i = get_pos()
  54. for x in range(i):
  55. self.dna[get_pos()] = get_ran()
  56. else :
  57. self.dna[which]=get_pos()
  58. def comp(self,other):
  59. """
  60. 计算与指定序列DNA的平方差
  61. """
  62. l = []
  63. val = 0
  64. for x in range(18):
  65. #print(x)
  66. d = self.dna[x] - other.dna[x]
  67. d = pow(d,2)
  68. l.append(d)
  69. val = val + d
  70. return l,val
  71. def cross(self,other):
  72. """
  73. 该染色体与其他染色体基因重组,产生新染色体,采用多点交叉
  74. """
  75. new = []
  76. for i in range(18):
  77. if get_pos(1) == 0:
  78. new.append(self.dna[i])
  79. else :
  80. new.append(other.dna[i])
  81. return Chromosome(new)
  82. class Population:
  83. """
  84. 种群类
  85. """
  86. def __init__(self,much=5000,aim=[72, 101, 108, 108, 111, 44, 105,99,106,98,64,102,111,120,109,97,105,108]):
  87. """
  88. 初始化种群,默认种群数量5000,指定序列为 Hello,icjb@foxmail
  89. """
  90. self.group = []
  91. self.best = Chromosome(aim)
  92. i = 0
  93. while i < much:
  94. self.group.append(Chromosome())
  95. i = i + 1
  96. def choice(self,p=0.05):
  97. """
  98. 选择操作,采用锦标赛选择方法,默认保留0.05
  99. """
  100. group = []
  101. old = self.group[:]
  102. count = int(self.group.__len__() * p)
  103. once = int(self.group.__len__() / count)
  104. t_b = old[0]
  105. t = 0
  106. for ch in old:
  107. if t == once:
  108. group.append(t_b)
  109. t_b = ch
  110. t = 0
  111. _,v1 = t_b.comp(self.best)
  112. _,v2 = ch.comp(self.best)
  113. if v1 >= v2 :
  114. t_b = ch
  115. t = t + 1
  116. self.group.clear()
  117. self.group = group[:]
  118. def cross(self,p=0.7):
  119. """
  120. 交叉操作,采用多点交叉
  121. """
  122. count = int(self.group.__len__()*p)
  123. i = 0
  124. group = []
  125. while i < count:
  126. t = self.group.__len__()
  127. group.append(self.group[get_pos(t-1)].cross(self.group[get_pos(t-1)]))
  128. i = i + 1
  129. self.group = self.group + group
  130. def mutation(self,p=0.001):
  131. """
  132. 种群突变
  133. """
  134. count = int(self.group.__len__()*p)
  135. i = 0
  136. t = self.group.__len__()
  137. while i < count:
  138. self.group[get_pos(t-1)].mutation()
  139. i = i + 1
  140. def have_the_best(self):
  141. """
  142. 判断是否存在目标序列
  143. """
  144. for ch in self.group:
  145. _,v = ch.comp(self.best)
  146. if v == 0 :
  147. return True
  148. return False
  149. def value(self):
  150. """
  151. 计算该种群的估值
  152. """
  153. val = 0
  154. for ch in self.group:
  155. _,v = ch.comp(self.best)
  156. val = val + v
  157. return val / self.group.__len__()
  158. def get_best(self):
  159. """
  160. 获取种群最优个体
  161. """
  162. best_one = self.group[0]
  163. _,val = best_one.comp(self.best)
  164. for ch in self.group:
  165. _,v = ch.comp(self.best)
  166. if val >= v :
  167. best_one = ch
  168. val = v
  169. return best_one
  170. def big_up(self):
  171. self.choice(0.9)
  172. self.cross(1.5)
  173. self.mutation(0.01)
  174. def big_down(self):
  175. self.choice()
  176. self.cross()
  177. self.mutation()
  178. def main():
  179. """
  180. 主函数
  181. """
  182. ch_b = Chromosome(best)
  183. po = Population(5000)
  184. i = 1
  185. vals = []
  186. popu = []
  187. while i <= 500:
  188. val = po.value()
  189. leng = po.group.__len__()
  190. str1 = '第 {:^4} 代: 数量为 {:^6}, 估值 :{:^6}'.format(i,leng,int(val))
  191. str2 = ' -- 最佳 : {}'.format(po.get_best().to_asc())
  192. if po.group.__len__() < 500:
  193. #种群个体少于500,需要补充大量新个体以免灭亡
  194. p1 = 0.8
  195. p2 = 1
  196. p3 = 0.12
  197. elif po.group.__len__() < 2500:
  198. p1 = 0.6
  199. p2 = 0.99
  200. p3 = 0.1
  201. elif po.group.__len__() < 5000:
  202. p1 = 0.5
  203. p2 = 0.9
  204. p3 = 0.09
  205. elif po.group.__len__() < 8000:
  206. p1 = 0.3
  207. p2 = 0.82
  208. p3 = 0.08
  209. elif po.group.__len__() < 10000:
  210. p1 = 0.2
  211. p2 = 0.78
  212. p3 = 0.05
  213. else :
  214. #默认操作
  215. p1 = 0.05
  216. p2 = 0.7
  217. p3 = 0.001
  218. # #但估值趋于稳定时,刺激种群
  219. # if val < 1000 :
  220. # p1 = p1 - 0.5
  221. # if p1 <= 0 :
  222. # p1 = 0.05
  223. # p2 = p2 + 0.3
  224. # p3 = p3 + 0.05
  225. #模拟突增突降,可选
  226. # if get_pos(100) < 5 :
  227. # po.big_down()
  228. # print('big-down')
  229. # if get_pos(100) > 95 :
  230. # po.big_up()
  231. # print('big-up')
  232. print(str1+str2)
  233. #print(str2)
  234. po.choice(p1)
  235. if po.have_the_best() :
  236. print('找到目标!')
  237. print(ch_b.to_asc())
  238. break
  239. po.cross(p2)
  240. po.mutation(p3)
  241. vals.append(val)
  242. popu.append(leng)
  243. i = i + 1
  244. #绘图
  245. plt.figure(1)
  246. plt.subplot(121)
  247. x = range(i-1)
  248. y = vals[:]
  249. plt.plot(x,y)
  250. plt.subplot(122)
  251. y = popu[:]
  252. plt.plot(x,y)
  253. plt.show()
  254. if __name__ == "__main__":
  255. """
  256. """
  257. main()
  258. input()

参考

遗传算法(python版) - 远方不远 - CSDN博客

一文读懂遗传算法工作原理(附Python实现)

【算法】超详细的遗传算法(Genetic Algorithm)解析 - 简书

遗传算法学习笔记(一):常用的选择策略 - 依然传奇 - 博客园

遗传算法选择策略比较 - 道客巴巴

基于遗传算法的人工智能实例之拼图游戏(python实现) - 不基调的博客 - CSDN博客

另一版本实现方式,改自GITHUB:

  1. import numpy as np
  2. import matplotlib as mpl
  3. import matplotlib.pyplot as plt
  4. import time
  5. from random import (choice, random, randint)
  6. __all__ = ['Chromosome', 'Population']
  7. class Chromosome:
  8. _target_gene = "Hello, icjb@foxmail.com"
  9. def __init__(self, gene):
  10. self.gene = gene
  11. self.fitness = Chromosome._update_fitness(gene)
  12. def mate(self, mate):
  13. pivot = randint(0, len(self.gene) - 1)
  14. gene1 = self.gene[:pivot] + mate.gene[pivot:]
  15. gene2 = mate.gene[:pivot] + self.gene[pivot:]
  16. return Chromosome(gene1), Chromosome(gene2)
  17. def mutate(self):
  18. gene = list(self.gene)
  19. delta = randint(44, 122)
  20. idx = randint(0, len(gene) - 1)
  21. gene[idx] = chr((ord(gene[idx]) + delta) % 123)
  22. return Chromosome(''.join(gene))
  23. @staticmethod
  24. def _update_fitness(gene):
  25. fitness = 0
  26. for a, b in zip(gene, Chromosome._target_gene):
  27. fitness += abs(ord(a) - ord(b))
  28. return fitness
  29. @staticmethod
  30. def gen_random():
  31. gene = []
  32. for x in range(len(Chromosome._target_gene)):
  33. gene.append(chr(randint(44, 122)))
  34. return Chromosome(''.join(gene))
  35. class Population:
  36. _tournamentSize = 3
  37. def __init__(self, size=1024, crossover=0.8, elitism=0.1, mutation=0.3):
  38. self.elitism = elitism
  39. self.mutation = mutation
  40. self.crossover = crossover
  41. buf = []
  42. for i in range(size): buf.append(Chromosome.gen_random())
  43. self.population = list(sorted(buf, key=lambda x: x.fitness))
  44. def _tournament_selection(self):
  45. best = choice(self.population)
  46. for i in range(Population._tournamentSize):
  47. cont = choice(self.population)
  48. if (cont.fitness < best.fitness): best = cont
  49. return best
  50. def _selectParents(self):
  51. return (self._tournament_selection(), self._tournament_selection())
  52. def evolve(self):
  53. size = len(self.population)
  54. idx = int(round(size * self.elitism))
  55. buf = self.population[:idx]
  56. while (idx < size):
  57. if random() <= self.crossover:
  58. (p1, p2) = self._selectParents()
  59. children = p1.mate(p2)
  60. for c in children:
  61. if random() <= self.mutation:
  62. buf.append(c.mutate())
  63. else:
  64. buf.append(c)
  65. idx += 2
  66. else:
  67. if random() <= self.mutation:
  68. buf.append(self.population[idx].mutate())
  69. else:
  70. buf.append(self.population[idx])
  71. idx += 1
  72. self.population = list(sorted(buf[:size], key=lambda x: x.fitness))
  73. if __name__ == "__main__":
  74. maxGenerations = 2000
  75. t1 = time.time()
  76. pop = Population(size=2000, crossover=0.7, elitism=0.05, mutation=0.9)
  77. li = []
  78. x = []
  79. for i in range(1, maxGenerations + 1):
  80. print("Generation %d Fitness:%d Result:%s" % (i, Chromosome._update_fitness(pop.population[0].gene),pop.population[0].gene) )
  81. if pop.population[0].fitness == 0: break
  82. else:pop.evolve()
  83. li.append(Chromosome._update_fitness(pop.population[0].gene))
  84. xx = 0
  85. for p in range(pop.population.__len__()):
  86. xx += Chromosome._update_fitness(pop.population[p].gene)
  87. xx = xx / pop.population.__len__()
  88. x.append(xx)
  89. x.sort()
  90. print(x[0])
  91. print("Maximum generations reached without success.")
  92. t2 = time.time()
  93. t = int(t2 - t1)
  94. print(f'+ 共用时: {t} s')
  95. plt.figure(1)
  96. plt.subplot(111)
  97. x = range(i-1)
  98. y = li[:]
  99. plt.plot(x,y)
  100. plt.xlabel("generation",fontsize=12)
  101. plt.ylabel("fitness",fontsize=12)
  102. plt.show()

Python 遗传算法实现字符串的更多相关文章

  1. Python中关于字符串的问题

    在Python里面,字符串相加经常会出现'ascii' codec can't decode byte 0xe7 in position 0: ordinal not in range(128)这样的 ...

  2. python出输出字符串方式:

    python出输出字符串方式: >>> who='knights' >>> what='NI' >>> print ('we are the',w ...

  3. Python学习笔记-字符串

    Python之使用字符串 1.所有的标准序列操作(索引,分片,乘法,判断成员资格,求长度,取最小值,最大值)对字符串同样适用.但是字符串都是不可变的. 2.字符串格式化使用字符串格式化操作符即%. f ...

  4. Python中Unicode字符串

    Python中Unicode字符串 字符串还有一个编码问题. 因为计算机只能处理数字,如果要处理文本,就必须先把文本转换为数字才能处理.最早的计算机在设计时采用8个比特(bit)作为一个字节(byte ...

  5. Python基础(二) —— 字符串、列表、字典等常用操作

    一.作用域 对于变量的作用域,执行声明并在内存中存在,该变量就可以在下面的代码中使用. 二.三元运算 result = 值1 if 条件 else 值2 如果条件为真:result = 值1如果条件为 ...

  6. Python补充05 字符串格式化 (%操作符)

    作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 在许多编程语言中都包含有格式化字符串的功能,比如C和Fortran语言中的格式化输 ...

  7. Python中的字符串处理

    Python转义字符 在需要在字符中使用特殊字符时,python用反斜杠(\)转义字符.如下表: 转义字符 描述 \(在行尾时) 续行符 \\ 反斜杠符号 \' 单引号 \" 双引号 \a ...

  8. Python学习笔记整理(四)Python中的字符串..

    字符串是一个有序的字符集合,用于存储和表现基于文本的信息. 常见的字符串常量和表达式 T1=‘’ 空字符串 T2="diege's" 双引号 T3=""&quo ...

  9. python中关于字符串的操作

    Python 字符串操作方法大全 python字符串操作实方法大合集,包括了几乎所有常用的python字符串操作,如字符串的替换.删除.截取.复制.连接.比较.查找.分割等,需要的朋友可以参考下 1. ...

随机推荐

  1. FileZila

    FileZilla下载文件失败的原因 对应访问的目录在服务器上没有权限下载 在本地没有切换到用户的家目录

  2. [转]【无私分享:ASP.NET CORE 项目实战(第十四章)】图形验证码的实现

    本文转自:http://www.cnblogs.com/yuangang/p/6000460.html 目录索引 [无私分享:ASP.NET CORE 项目实战]目录索引 简介 很长时间没有来更新博客 ...

  3. siteserver学习笔记

    1.安装 安装前的准备工作 参考https://docs.siteserver.cn/getting-started/#/how-to-install-siteserver-cms官网的文档写的很详细 ...

  4. js报错

    1.如果出现找不到js方法,感觉写的js都正确就是调试报错,可能原因是js文件重复引用 2.在用ajax异步提交时千万别用 submit 控件,submit控件是表单提交控件,提交表单的同时不会执行异 ...

  5. jQuery中的节点操作(一)

    html代码如下 <p>Dom操作练习</p> jQuery插入节点 $("p").append("武汉php"); //向每个匹配的元 ...

  6. Linux 学习 之 bash

    Anything is programmable with defined syntax and common lib. Bash Shell is created to programme to L ...

  7. ArcGIS Desktop中面与面之间空隙填充

    1.前言 再给客户培训过程中被问到这样一个问题,几个面中间有一个空心部分(如下图所示),如何快速绘制中心部分的要素. 2.操作流程 1.打开Editor工具栏,开始编辑操作. 2.点击创建要素按钮,打 ...

  8. 解决javascript四舍五入不准确

    function roundFixed(num, fixed) { var pos = num.toString().indexOf('.'), decimal_places = num.toStri ...

  9. [Maven]Eclipse集成遇到的问题

    当maven项目导入到eclipse中后使用eclipse提供的maven命令执行任意一个出现 Exception in thread "main" java.lang.Unsup ...

  10. CentOS 7.0 各版本下载说明 新增Everything版

    CentOS-7.0-1406有很多可供选择的版本,对初学者来说,不知如何选择,下面做简单的介绍: CentOS-7.0-1406-x86_64-DVD.iso 标准安装版,一般下载这个就可以了 Ce ...