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个数,直到恢复到设置的种群规模。在基因突变部分,不再是往种群中添加新的个体,而是修改现有种群的基因。
#coding=utf-8
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
import random best = [72, 101, 108, 108, 111, 44, 105,99,106,98,64,102,111,120,109,97,105,108]
#最佳序列 def get_ran(b=33,e=126):
"""
获取随机字符值,默认从可显示字符开始(33-126)
"""
return random.randint(b,e) def get_pos(cou=17):
"""
获取随机位置,默认到17
"""
return random.randint(0,cou) class Chromosome:
"""
染色体类
""" def __init__(self,dna=None):
"""
初始化,可指定DNA序列顺序,默认DNA为随机序列。
"""
if dna is not None:
self.dna = dna[:]
else :
self.dna = []
for i in range(18):
self.dna.append(get_ran()) def to_asc(self):
"""
将DNA序列由int转为str
"""
str = ''
for chrx in self.dna:
str = str + chr(chrx)
return str def __str__(self):
"""
将DNA序列由int转为str
"""
str = ''
for chrx in self.dna:
str = str + chr(chrx)
return str def mutation(self,which=-1):
"""
变异操作,默认产生随机个变异位点,突变为随机值,可指定突变位置
"""
if which == -1 :
i = get_pos()
for x in range(i):
self.dna[get_pos()] = get_ran()
else :
self.dna[which]=get_pos() def comp(self,other):
"""
计算与指定序列DNA的平方差
"""
l = []
val = 0
for x in range(18):
#print(x)
d = self.dna[x] - other.dna[x]
d = pow(d,2)
l.append(d)
val = val + d
return l,val def cross(self,other):
"""
该染色体与其他染色体基因重组,产生新染色体,采用多点交叉
"""
new = []
for i in range(18):
if get_pos(1) == 0:
new.append(self.dna[i])
else :
new.append(other.dna[i])
return Chromosome(new) class Population:
"""
种群类
""" def __init__(self,much=5000,aim=[72, 101, 108, 108, 111, 44, 105,99,106,98,64,102,111,120,109,97,105,108]):
"""
初始化种群,默认种群数量5000,指定序列为 Hello,icjb@foxmail
"""
self.group = []
self.best = Chromosome(aim)
i = 0
while i < much:
self.group.append(Chromosome())
i = i + 1 def choice(self,p=0.05):
"""
选择操作,采用锦标赛选择方法,默认保留0.05
"""
group = []
old = self.group[:]
count = int(self.group.__len__() * p)
once = int(self.group.__len__() / count)
t_b = old[0]
t = 0
for ch in old:
if t == once:
group.append(t_b)
t_b = ch
t = 0
_,v1 = t_b.comp(self.best)
_,v2 = ch.comp(self.best)
if v1 >= v2 :
t_b = ch
t = t + 1
self.group.clear()
self.group = group[:] def cross(self,p=0.7):
"""
交叉操作,采用多点交叉
"""
count = int(self.group.__len__()*p)
i = 0
group = []
while i < count:
t = self.group.__len__()
group.append(self.group[get_pos(t-1)].cross(self.group[get_pos(t-1)]))
i = i + 1
self.group = self.group + group def mutation(self,p=0.001):
"""
种群突变
"""
count = int(self.group.__len__()*p)
i = 0
t = self.group.__len__()
while i < count:
self.group[get_pos(t-1)].mutation()
i = i + 1 def have_the_best(self):
"""
判断是否存在目标序列
"""
for ch in self.group:
_,v = ch.comp(self.best)
if v == 0 :
return True
return False def value(self):
"""
计算该种群的估值
"""
val = 0
for ch in self.group:
_,v = ch.comp(self.best)
val = val + v
return val / self.group.__len__() def get_best(self):
"""
获取种群最优个体
"""
best_one = self.group[0]
_,val = best_one.comp(self.best)
for ch in self.group:
_,v = ch.comp(self.best)
if val >= v :
best_one = ch
val = v
return best_one def big_up(self):
self.choice(0.9)
self.cross(1.5)
self.mutation(0.01) def big_down(self):
self.choice()
self.cross()
self.mutation() def main():
"""
主函数
"""
ch_b = Chromosome(best)
po = Population(5000)
i = 1
vals = []
popu = []
while i <= 500:
val = po.value()
leng = po.group.__len__()
str1 = '第 {:^4} 代: 数量为 {:^6}, 估值 :{:^6}'.format(i,leng,int(val))
str2 = ' -- 最佳 : {}'.format(po.get_best().to_asc())
if po.group.__len__() < 500:
#种群个体少于500,需要补充大量新个体以免灭亡
p1 = 0.8
p2 = 1
p3 = 0.12
elif po.group.__len__() < 2500:
p1 = 0.6
p2 = 0.99
p3 = 0.1
elif po.group.__len__() < 5000:
p1 = 0.5
p2 = 0.9
p3 = 0.09
elif po.group.__len__() < 8000:
p1 = 0.3
p2 = 0.82
p3 = 0.08
elif po.group.__len__() < 10000:
p1 = 0.2
p2 = 0.78
p3 = 0.05
else :
#默认操作
p1 = 0.05
p2 = 0.7
p3 = 0.001 # #但估值趋于稳定时,刺激种群
# if val < 1000 :
# p1 = p1 - 0.5
# if p1 <= 0 :
# p1 = 0.05
# p2 = p2 + 0.3
# p3 = p3 + 0.05 #模拟突增突降,可选
# if get_pos(100) < 5 :
# po.big_down()
# print('big-down')
# if get_pos(100) > 95 :
# po.big_up()
# print('big-up') print(str1+str2)
#print(str2)
po.choice(p1)
if po.have_the_best() :
print('找到目标!')
print(ch_b.to_asc())
break
po.cross(p2)
po.mutation(p3)
vals.append(val)
popu.append(leng)
i = i + 1 #绘图
plt.figure(1)
plt.subplot(121)
x = range(i-1)
y = vals[:]
plt.plot(x,y)
plt.subplot(122)
y = popu[:]
plt.plot(x,y)
plt.show() if __name__ == "__main__":
"""
"""
main()
input()

参考

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

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

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

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

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

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

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

import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
import time from random import (choice, random, randint) __all__ = ['Chromosome', 'Population'] class Chromosome:
_target_gene = "Hello, icjb@foxmail.com"
def __init__(self, gene):
self.gene = gene
self.fitness = Chromosome._update_fitness(gene) def mate(self, mate):
pivot = randint(0, len(self.gene) - 1)
gene1 = self.gene[:pivot] + mate.gene[pivot:]
gene2 = mate.gene[:pivot] + self.gene[pivot:]
return Chromosome(gene1), Chromosome(gene2) def mutate(self):
gene = list(self.gene)
delta = randint(44, 122)
idx = randint(0, len(gene) - 1)
gene[idx] = chr((ord(gene[idx]) + delta) % 123) return Chromosome(''.join(gene)) @staticmethod
def _update_fitness(gene):
fitness = 0
for a, b in zip(gene, Chromosome._target_gene):
fitness += abs(ord(a) - ord(b))
return fitness @staticmethod
def gen_random():
gene = []
for x in range(len(Chromosome._target_gene)):
gene.append(chr(randint(44, 122))) return Chromosome(''.join(gene)) class Population:
_tournamentSize = 3
def __init__(self, size=1024, crossover=0.8, elitism=0.1, mutation=0.3):
self.elitism = elitism
self.mutation = mutation
self.crossover = crossover
buf = []
for i in range(size): buf.append(Chromosome.gen_random())
self.population = list(sorted(buf, key=lambda x: x.fitness)) def _tournament_selection(self):
best = choice(self.population)
for i in range(Population._tournamentSize):
cont = choice(self.population)
if (cont.fitness < best.fitness): best = cont return best def _selectParents(self):
return (self._tournament_selection(), self._tournament_selection()) def evolve(self):
size = len(self.population)
idx = int(round(size * self.elitism))
buf = self.population[:idx] while (idx < size):
if random() <= self.crossover:
(p1, p2) = self._selectParents()
children = p1.mate(p2)
for c in children:
if random() <= self.mutation:
buf.append(c.mutate())
else:
buf.append(c)
idx += 2
else:
if random() <= self.mutation:
buf.append(self.population[idx].mutate())
else:
buf.append(self.population[idx])
idx += 1 self.population = list(sorted(buf[:size], key=lambda x: x.fitness)) if __name__ == "__main__":
maxGenerations = 2000
t1 = time.time()
pop = Population(size=2000, crossover=0.7, elitism=0.05, mutation=0.9)
li = []
x = []
for i in range(1, maxGenerations + 1):
print("Generation %d Fitness:%d Result:%s" % (i, Chromosome._update_fitness(pop.population[0].gene),pop.population[0].gene) )
if pop.population[0].fitness == 0: break
else:pop.evolve()
li.append(Chromosome._update_fitness(pop.population[0].gene))
xx = 0
for p in range(pop.population.__len__()):
xx += Chromosome._update_fitness(pop.population[p].gene)
xx = xx / pop.population.__len__()
x.append(xx)
x.sort()
print(x[0])
print("Maximum generations reached without success.")
t2 = time.time()
t = int(t2 - t1)
print(f'+ 共用时: {t} s')
plt.figure(1)
plt.subplot(111)
x = range(i-1)
y = li[:]
plt.plot(x,y)
plt.xlabel("generation",fontsize=12)
plt.ylabel("fitness",fontsize=12)
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. DEDE模板中如何运行php脚本和php变量的使用

    在使用dede模板的时候,经常会需要直接对dede数据库的底层字段进行处理,如果dede中没有相应的函数的时候,往往就需要我们想办法来处理了. 举例:我想取出数据表addonimages中的某一条记录 ...

  2. oracle 找回被覆盖的存储过程

    登录到sys账户下 1.TO_TIMESTAMP('2014-05-04 14:33:00', 'YYYY-MM-DD HH24:MI:SS') 删除前的日期 2.owner 表空调 3.Name   ...

  3. Java学习笔记--继承和多态(下)

    1.通过继承来开发超类(superclass) 2.使用super 关键词唤起超类的构造方法 3.在超类中覆盖方法 4.区分override和overload 5.在Object类中探索toStrin ...

  4. c#-day02学习笔记

    类型转化 为什么要类型转化:因为C#语言是强类型的语言,所以区分了很多的类型,类型和类型之间是不能直接赋值的,如果要赋值 就需要转换类型 类型转换分为两大类: 第一类:隐式转换 隐式转换是系统默认的转 ...

  5. MVC切片编程

    在商城网站中,用户中心的每个页面都要几乎都要涉及对用户是否登录的判断,为了减少代码重写,可采用切片编程 using System; using System.Collections.Generic; ...

  6. vue学习第一天 ------ 临时笔记

    学习链接 Vue2+VueRouter2+Webpack+Axios 构建项目实战2017重制版(一)基础知识概述 http://blog.csdn.net/fungleo/article/detai ...

  7. jQuery实现焦点图[兼容ie7+]

    HTML: <div class="freehand" id="freehand"> <h1>宠物手绘</h1> <d ...

  8. python模块详解 random os

    random模块 常用方法 random.random() 随机产生一个小于1的浮点数 import random print(random.random()) #0.4153761818276826 ...

  9. Struts2_简单数据验证

    在Action 中添加 FieldError if(name == null || !name.equals("admin")){ this.addFieldError(" ...

  10. Java—常量和变量

    关键字 Java中有特殊用途的词被称为关键字,关键字服务大小写. 标识符 标识符是用于给java程序中的变量.类.方法等命名的符号. 标识符的几条规则: 由字母.数字.下划线(_).美元符号($)组成 ...