文章目录

  • 一.问题定义、个体编码与创建初始种群
    • 1.优化问题定义
    • 2.个体编码
    • 3.初始族群的创建
  • 二.评价
  • 三.选择操作
    • 1.DEAP内置的选择操作
    • 2.常用选择介绍
    • 3.选择操作代码示例
  • 四.交叉
    • 1.DEAP内置的交叉操作(crossover)操作
    • 2.常用交叉操作介绍
    • 3.交叉操作代码示例
  • 五.变异
    • 1.DEAP内置的突变(Mutation)操作
    • 2.常用突变介绍
    • 3.突变操作代码示例
  • 六.环境选择

一.问题定义、个体编码与创建初始种群

1.优化问题定义

单目标优化

creator.create('FitnessMin', base.Fitness, weights=(-1.0, ))

在创建单目标优化问题时,weights用来指示最大化和最小化。此处-1.0即代表问题是一个最小化问题,对于最大化,应将weights改为正数,如1.0。
另外即使是单目标优化,weights也需要是一个tuple,以保证单目标和多目标优化时数据结构的统一。
对于单目标优化问题,weights 的绝对值没有意义,只要符号选择正确即可。

多目标优化

creator.create('FitnessMulti', base.Fitness, weights=(-1.0, 1.0))

对于多目标优化问题,weights用来指示多个优化目标之间的相对重要程度以及最大化最小化。如示例中给出的(-1.0, 1.0)代表对第一个目标函数取最小值,对第二个目标函数取最大值。

2.个体编码

实数编码(Value encoding):直接用实数对变量进行编码。优点是不用解码,基因表达非常简洁,而且能对应连续区间。但是实数编码后搜索区间连续,因此容易陷入局部最优。

实数编码的DEAP实现

'''creator是允许创建可以满足您的进化算法需求的类,实际上,可以从任何可以想象的类型(从列表到集合,dict,PrimitiveTree等)构建新的类,从而提供了实现遗传算法,遗传编程,进化策略,粒子群优化器等的可能性deap.creator.create(name, base[, attribute[, ...]])从creator模块中创建一个新的名为name的类,该类从base继承name:要创建类的名称base:继承的基类attribute:在此类的实例上添加的一个或多个属性deap.base.Fitness([values])如果将值作为元组提供,则使用这些值初始化适应度,否则为空  values:适应度的初始值作为元组 deap.base.Toolbox()包含演化运算符的演化工具箱clone()方法,该方法复制作为参数传递的任何元素,该方法默认为copy.deepcopy()函数map()方法,该方法将作为第一个参数给出的函数应用于作为下一个参数给出的可迭代对象的每个项目,该方法默认为map()函数register()方法用其他函数填充工具箱register(alias, method[, argument[, ...]])在alias name下注册一个函数,您可以提供默认参数,这些默认参数将在调用注册函数时自动传递。然后可以在函数调用时覆盖固定参数参数:alias:操作符在toolbox中接受的名称,如果别名已经存在,它将覆盖已经存在的操作符method:函数argument:一个或多个参数在调用时自动传递给已注册的函数tools.initRepeat(container, func, n)调用函数func n次,并在容器类型的容器中返回结果参数:container:从func放入数据的类型func:这个函数将被调用n次来填充容器n:重复func的次数返回:容器实例,其中填充了func的数据
'''from deap import creator,base,tools
import numpy as npsize = 5
creator.create('FitnessMin',base.Fitness,weights=(-1,)) # 单目标优化求最小值
creator.create('Individual',list,fitness = creator.FitnessMin)  # 创建Individual类,继承listtoolbox = base.Toolbox()
toolbox.register('Attr_float',np.random.rand)
# creator.Individual容器类型,toolbox.Attr_float函数
toolbox.register('Individual',tools.initRepeat,creator.Individual,toolbox.Attr_float,n=size)ind = toolbox.Individual()
print(ind)# [0.38990108948604063, 0.4021053788901321, 0.9262767512903585, 0.8699811269656622, 0.85975277694355]

二进制编码
在二进制编码中,用01两种数字模拟人类染色体中的碱基,用一定长度的01字符串来描述变量。
其优点在于种群多样性大,
但是需要解码,而且不连续,容易产生Hamming cliff(例如0111=7, 1000=8,改动了全部的4位数字之后,实际值只变动了1),在接近局部最优位置时,染色体稍有变动,就会使变量产生很大偏移(格雷编码(Gray coding)能够克服汉明距离的问题,但是实际问题复杂度较大时,格雷编码很难精确描述问题)。

变量的二进制编码:
由于通常情况下,搜索空间都是实数空间,因此在编码时,需要建立实数空间到二进制编码空间的映射。使用二进制不能对实数空间进行连续编码,但是可以在给定精度下对连续空间进行离散化。

例子来说明如何对变量进行二进制编码,假设需要对一个在区间[-2, 2]上的变量进行二进制编码:

选择编码长度:在需要6位精度的情况下,我们需要将该区间离散为(2+2) * 10^6个数。由于2 ^ 22 > 4*10 ^ 6,我们至少需要22位二进制数字来满足我们的精度要求。

设置解码器:将二进制数字x^bin转化为十进制x ^dec之后(在python中可以用int(‘Binary number’, 2)来实现),按照公式解码,

就可以得到一个在[-2,2]区间内的实数。
二进制编码的DEAP实现
以随机生成一个长度为10的二进制编码为例,本身DEAP库中没有内置的Binary encoding,我们借助Scipy模块中的伯努利分布来生成一个二进制序列。

from deap import base,creator,tools
from scipy.stats import bernoulli   # 伯努利分布creator.create('FitnessMin',base.Fitness,weights=(-1.0,))   # 单目标优化
creator.create('Individual',list,fitness=creator.FitnessMin)gen_size = 10toolbox = base.Toolbox()
# bernoulli.rvs:生成随机数
toolbox.register('Binary',bernoulli.rvs,0.5)    # 概率为0.5
toolbox.register('Individual',tools.initRepeat,creator.Individual,toolbox.Binary,n=gen_size)ind = toolbox.Individual()
print(ind)
# [1, 0, 1, 0, 0, 0, 1, 0, 0, 0]

序列编码
通常在求解顺序问题时用到,例如TSP问题,序列编码的每个染色体都是一个序列
序列编码的DEAP实现

'''
通常在求解顺序问题时用到,序列编码中每个染色体都是一个序列deap.tools.initIterate(container, generator)以iterable作为唯一参数调用函数容器,该Iterable必须由方法或对象生成器返回参数:container:从func放入数据的类型generator:可迭代的函数(列表,元组等),该可迭代的内容将填充容器返回:容器的实例,其中填充了来自生成器的数据此辅助功能可以与Toolbox结合使用,以将填充容器的生成器注册为individual'''
from deap import base,creator,tools
import numpy as np
import randomcreator.create('FitnessMin',base.Fitness,weights=(-1.0,))   # 单变量优化
creator.create('Individual',list,fitness=creator.FitnessMin)
# np.random.permutation
size =10
toolbox = base.Toolbox()
toolbox.register('Indices',random.sample,range(size),size)
toolbox.register('Individual',tools.initIterate,creator.Individual,toolbox.Indices)
ind = toolbox.Individual()print(ind)
#[0, 1, 3, 6, 2, 8, 7, 4, 5, 9]

粒子
粒子是一种特殊个体,主要用于粒子群算法。相对于普通的个体,它额外具有速度、速度限制并且能记录最优位置。
粒子DEAP实现

'''粒子相对于普通个体,它额外具有速度、速度限制并且能记录最优位置
'''
from deap import base,creator,tools
import numpy as np
import random# 创建实例
creator.create('FitnessMax',base.Fitness,weights=(1.0,1.0))     # 多目标优化求最大值
creator.create('Particle',list,fitness = creator.FitnessMax,speed=None,smin=None,smax=None,best=None)# 自定义的粒子初始化函数
def initParticle(pcls,size,pmin,pmax,smin,smax):part = pcls(random.uniform(pmin,pmax) for _ in range(size))# part = pcls(np.random.uniform(low=pmin,high=pmax,size=size))part.speed = [random.uniform(smin,smax) for _ in range(size)]part.smin = sminpart.smax = smaxreturn parttoolbox = base.Toolbox()
# 为自己编写的initParticle函数注册一个alias "Particle",调用时生成一个2维粒子,放在容器creator.Particle中,
# 粒子的位置落在(-6,6)中,速度限制为(-3,3)
toolbox.register('Particle',initParticle,creator.Particle,size=2,pmin=-6,pmax=6,smin=-3,smax=3)ind = toolbox.Particle()
print(ind)
print(ind.speed)
print(ind.smin,ind.smax)# [-0.5091176056711042, -3.411699051528683]
# [1.9910066837235334, 0.238618206895568]
# -3 3# [-4.512169085697154, -3.3189384493833614]
# [-2.18937298561473, 0.9288041818827244]
# -3 3print(ind.fitness.valid)
# 结果为False,因为当前还没有计算适应度函数,所以粒子的最优适应度值还是invalid

3.初始族群的创建

一般族群
这是最常用的族群类型,族群中没有特别的顺序或者子族群
一般族群的DEAP实现
以二进制编码为例,以下代码生成由10个长度为5的随机二进制编码个体组成的一般族群

from scipy.stats import bernoulli
from deap import base,creator,tools
import numpy as np# 定义问题
creator.create('FitnessMin',base.Fitness,weights=(-1.0,))   # 单目标优化最小值
creator.create('Individual',list,fitness = creator.FitnessMin)# 生成个体
gene_size = 5
toolbox = base.Toolbox()
toolbox.register('Binary',bernoulli.rvs,0.5)
toolbox.register('Individual',tools.initRepeat,creator.Individual,toolbox.Binary,n = gene_size)# 生成初始族群
N_pop = 10
toolbox.register('Population',tools.initRepeat,list,toolbox.Individual)
ind = toolbox.Population(n=N_pop)print(ind)
# [[1, 1, 1, 1, 1], [1, 1, 0, 0, 0], [1, 1, 0, 0, 0], [0, 1, 1, 0, 0], [1, 1, 1, 0, 1], [0, 1, 0, 0, 1], [1, 1, 1, 1, 0], [0, 0, 0, 0, 0], [1, 0, 1, 0, 0], [0, 0, 1, 0, 0]]
ind = np.array(ind).reshape(-1,5)
print(ind)
# [[1 1 1 1 1]
#  [1 1 0 0 0]
#  [1 1 0 0 0]
#  [0 1 1 0 0]
#  [1 1 1 0 1]
#  [0 1 0 0 1]
#  [1 1 1 1 0]
#  [0 0 0 0 0]
#  [1 0 1 0 0]
#  [0 0 1 0 0]]

同类群
同类群即一个族群中包含几个子族群。在有些算法中,会使用本地选择(Local selection)挑选育种个体,这种情况下个体仅与同一个邻域的个体相互作用
同类群的DEAP实现

from scipy.stats import bernoulli
from deap import base,creator,tools
import numpy as np# 定义问题
creator.create('FitnessMin',base.Fitness,weights=(-1.0,))   # 单目标优化问题
creator.create('Individual',list,fitness = creator.FitnessMin)# 生成个体
gen_size = 5
toolbox = base.Toolbox()
toolbox.register('Binary',bernoulli.rvs,0.5)
toolbox.register('Individual',tools.initRepeat,creator.Individual,toolbox.Binary,n=gen_size)# 生成同类群
toolbox.register('deme',tools.initRepeat,list,toolbox.Individual)deme_size = 10,50,100
population = [toolbox.deme(n=i) for i in deme_size]print(population)
# [[[1, 1, 1, 1, 1], [0, 1, 1, 0, 1], [0, 0, 0, 0, 0], [0, 1, 1, 1, 0], [0, 1, 1, 0, 0], [0, 1, 1, 0, 1], [0, 1, 1, 1, 1], [1, 0, 1, 0, 0], [0, 1, 0, 0, 0], [1, 0, 0, 0, 1]], [[1, 0, 0, 0, 0], [1, 1, 0, 1, 0], [0, 0, 1, 1, 1], [0, 0, 0, 0, 1], [0, 0, 1, 1, 0], [1, 1, 1, 0, 1], [0, 1, 0, 1, 0], [0, 1, 0, 0, 0], [1, 1, 1, 1, 1], [1, 1, 1, 0, 0], [0, 1, 1, 1, 0], [0, 0, 1, 0, 0], [1, 1, 0, 1, 1], [1, 0, 1, 0, 0], [0, 0, 0, 0, 0], [1, 0, 1, 1, 1], [0, 0, 1, 0, 0], [0, 0, 1, 1, 1], [0, 0, 0, 1, 1], [1, 0, 0, 0, 0], [0, 0, 0, 0, 1], [0, 1, 1, 0, 1], [1, 0, 1, 0, 1], [1, 1, 1, 0, 0], [0, 0, 1, 0, 0], [0, 1, 0, 0, 1], [0, 0, 0, 0, 0], [0, 0, 1, 1, 1], [1, 0, 1, 1, 1], [0, 1, 0, 0, 1], [1, 0, 1, 1, 1], [0, 1, 1, 0, 1], [1, 1, 0, 0, 0], [0, 1, 0, 0, 1], [1, 1, 1, 0, 1], [1, 0, 1, 0, 0], [0, 0, 0, 1, 1], [1, 1, 0, 1, 0], [1, 0, 0, 0, 1], [0, 1, 1, 1, 1], [1, 0, 0, 1, 0], [1, 0, 0, 1, 0], [0, 1, 0, 1, 1], [1, 0, 0, 1, 1], [0, 1, 0, 1, 1], [1, 1, 1, 1, 1], [1, 1, 1, 0, 0], [1, 0, 1, 0, 0], [0, 1, 1, 1, 1], [0, 0, 0, 1, 0]], [[0, 1, 0, 0, 0], [0, 1, 1, 0, 1], [0, 0, 1, 0, 1], [0, 0, 1, 1, 1], [0, 1, 1, 0, 1], [0, 0, 0, 1, 0], [0, 0, 0, 1, 0], [0, 0, 0, 1, 1], [1, 0, 1, 0, 0], [1, 1, 0, 0, 1], [0, 1, 1, 0, 1], [0, 1, 0, 0, 0], [1, 1, 1, 1, 1], [1, 1, 0, 0, 0], [0, 0, 1, 0, 1], [1, 0, 0, 0, 1], [1, 1, 0, 1, 1], [0, 0, 1, 1, 0], [0, 1, 0, 1, 0], [1, 1, 0, 1, 1], [1, 1, 0, 1, 0], [0, 0, 1, 0, 1], [1, 0, 1, 0, 1], [0, 1, 0, 1, 1], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [1, 0, 0, 0, 1], [0, 0, 0, 1, 1], [0, 1, 0, 0, 0], [1, 0, 1, 1, 0], [0, 1, 1, 1, 1], [1, 0, 0, 0, 0], [0, 1, 0, 0, 0], [0, 0, 1, 1, 1], [1, 1, 0, 1, 1], [1, 0, 1, 0, 0], [1, 0, 1, 1, 1], [0, 0, 1, 0, 1], [1, 0, 0, 1, 1], [0, 1, 1, 1, 1], [1, 1, 1, 1, 0], [1, 1, 0, 1, 0], [0, 1, 0, 1, 0], [0, 1, 1, 0, 1], [1, 0, 1, 1, 1], [1, 1, 0, 1, 0], [0, 1, 1, 0, 1], [1, 1, 0, 0, 0], [0, 0, 1, 0, 0], [0, 1, 1, 1, 0], [0, 1, 1, 0, 0], [1, 1, 0, 0, 0], [1, 1, 1, 1, 1], [0, 1, 0, 1, 1], [1, 1, 0, 1, 1], [0, 1, 0, 0, 0], [0, 1, 1, 1, 0], [0, 1, 0, 1, 0], [1, 1, 1, 1, 0], [1, 0, 1, 0, 0], [0, 0, 1, 1, 1], [0, 1, 0, 0, 1], [1, 1, 1, 0, 1], [0, 1, 0, 0, 0], [1, 0, 0, 0, 0], [0, 1, 1, 0, 0], [0, 0, 1, 1, 0], [0, 1, 1, 0, 1], [0, 1, 0, 1, 1], [1, 0, 0, 1, 0], [1, 1, 0, 1, 1], [0, 1, 1, 1, 0], [0, 1, 1, 1, 0], [1, 1, 0, 1, 0], [0, 1, 1, 1, 1], [0, 0, 1, 1, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 1], [1, 1, 1, 1, 0], [1, 0, 1, 1, 1], [0, 0, 0, 1, 0], [0, 0, 1, 0, 1], [1, 1, 1, 1, 0], [1, 0, 1, 0, 0], [0, 1, 0, 1, 1], [0, 0, 0, 0, 1], [0, 1, 0, 0, 1], [1, 1, 0, 0, 0], [0, 0, 1, 0, 0], [0, 1, 0, 1, 1], [1, 0, 0, 1, 1], [1, 0, 0, 0, 0], [1, 0, 1, 1, 0], [0, 1, 0, 0, 1], [1, 1, 0, 1, 1], [0, 1, 0, 1, 0], [1, 0, 0, 1, 0], [0, 1, 1, 1, 1], [0, 1, 0, 0, 0], [1, 1, 0, 0, 1]]]

粒子群
粒子群中所有粒子共享全局最优。在实现时需要额外传入全局最优位置与全局最优适应度给族群。
粒子群的DEAP实现

'''算法迭代时,需要更新该轮迭代中最优位置和最优适应度
'''
from scipy.stats import bernoulli
from deap import creator,base,toolsfrom deap import base,creator,tools
import numpy as np
import random# 创建实例
creator.create('FitnessMax',base.Fitness,weights=(1.0,1.0))     # 多目标优化求最大值
creator.create('Particle',list,fitness = creator.FitnessMax,speed=None,smin=None,smax=None,best=None)# 自定义的粒子初始化函数
def initParticle(pcls,size,pmin,pmax,smin,smax):# part = pcls(random.uniform(pmin,pmax) for _ in range(size))part = pcls(np.random.uniform(low=pmin,high=pmax,size=size))part.speed = [random.uniform(smin,smax) for _ in range(size)]part.smin = sminpart.smax = smaxreturn parttoolbox = base.Toolbox()
# 为自己编写的initParticle函数注册一个alias "Particle",调用时生成一个2维粒子,放在容器creator.Particle中,
# 粒子的位置落在(-6,6)中,速度限制为(-3,3)
toolbox.register('Particle',initParticle,creator.Particle,size=2,pmin=-6,pmax=6,smin=-3,smax=3)creator.create('Swarm',list,gbest=None,gbestfit=creator.FitnessMax)
toolbox.register('swarm', tools.initRepeat, creator.Swarm, toolbox.Particle)ind = toolbox.swarm(n=10)
print(ind)# 生成10个二维粒子
# [[5.200304148961134, 3.4213399206695705], [3.8944090824509114, -3.88745134526645], [-2.9514487706857992, -4.304590950219268], [3.450157870566315, 1.642318575999842], [1.2612015164914165, 2.795146317474739], [3.3333351993489586, -1.2831641529678635], [3.728597597972149, 3.164079972288679], [2.3048321859467826, -1.3671834158126241], [-4.5201070374662775, 5.394044091350391], [5.162017907192103, -2.0265946827646792]]

二.评价

评价部分是根据任务的特性高度定制的,DEAP库中没有预置的评价函数模板。
使用DEAP时,需要注意的是:无论是单目标还是多目标优化,评价函数的返回值必须是一个tuple类型。
简单的例子

import numpy as np
from scipy.stats import bernoulli
from deap import base,creator,tools# 定义问题
creator.create('FitnessMin',base.Fitness,weights=(-1.0,))    # 单目标优化,求最小值
creator.create('Individual',list,fitness=creator.FitnessMin)# 生成个体
gen_size = 5
toolbox = base.Toolbox()
toolbox.register('Attr_float',np.random.rand)
toolbox.register('Individual',tools.initRepeat,creator.Individual,toolbox.Attr_float,n = gen_size)# 生成初始族群
pop_size =10
toolbox.register('Population',tools.initRepeat,list,toolbox.Individual)
pop = toolbox.Population(n=pop_size)# 定义评价函数
def evaluate(individual):return sum(individual),     # 注意这个逗号,即使是单变量优化问题,也需要返回tuple# 评价初始族群
toolbox.register('Evaluate',evaluate)
fitnesses = map(toolbox.Evaluate,pop)
for ind,fit in zip(pop,fitnesses):# 适应度ind.fitness.values = fitprint(ind.fitness.values)# (2.799073230362443,)
# (3.182562718729237,)
# (2.666247235597166,)
# (1.3358638076609075,)
# (3.1632687857686936,)
# (2.3002100285403086,)
# (2.7960543695400584,)
# (1.9780333514536967,)
# (3.48145577698652,)
# (1.984007510985768,)

三.选择操作

1.DEAP内置的选择操作

DEAP的tools模块中内置了13种选择操作,对全部选择算子的描述可参考官方文档

2.常用选择介绍

下面介绍一些常用的配种选择操作
锦标赛选择

deap.tools.selTournament(individuals, k, tournsize, fit_attr = 'fitness')

锦标赛选择顾名思义,就是模拟锦标赛的方式,首先在族群中随机抽取tournsize个个体,然后从中选取具有最佳适应度的个体,将此过程重复k次,获得育种族群。tournsize越大,选择强度(selection intensity)越高,在选择之后留下的育种族群的平均适应度也就越高。比较常用的tournsize是2。

下图给出了由5个个体构成的族群中进行一次tournsize为3的锦标赛选择的过程。


锦标赛选择相比于轮盘赌选择,通常能够有更快的收敛速度,在实际场景中应用较多。
轮盘赌选择

deap.tools.selRoulette(individuals, k, fit_attr = 'fitness')

轮盘赌选择是最常见的选择策略,它可以看作是有放回的随机抽样。
在轮盘赌选择中,每个个体ai被选中的概率P(ai)与其适应度函数f(ai)成正比


注意在适应度可能为负数时,不适合用轮盘赌选择。

在实际应用中,很多文章都指出轮盘赌选择的性能较差,在通常情况下都不如随机抽样选择和锦标赛选择。
随机普遍抽样选择

deap.tools.selStochasticUniversalSampling(individuals, k,
fit_attr = 'fitness')

随机普遍抽样选择是一种有多个指针的轮盘赌选择,其优点是能够保存族群多样性,而不会像轮盘赌一样,有较大几率对重复选择最优个体。

NSGA-II选择

deap.tools.selNSGA2(individuals, k, nd = 'standard')

NSGA-II全称为 Nondominated sorting genetic algorithm II,是Kalyanmoy Deb于2002年提出的。该方法解决了前代NSGA的三个痛点:计算复杂度高;缺少精英选择;需要给定额外参数值。

在使用该函数时,需要注意族群中个体数量必须要比k值大,因为在该算法中,每个个体在返回的选择列表中至多出现一次。

基于排序的选择算法
Linear ranking selection, Exponential ranking selection等,在DEAP中都没有给出直接的函数,需要自己实现。

3.选择操作代码示例

锦标赛选择

import numpy as np
from scipy.stats import bernoulli
from deap import base,creator,tools# 定义问题
creator.create('FitnessMin',base.Fitness,weights=(-1.0,))    # 单目标优化,求最小值
creator.create('Individual',list,fitness=creator.FitnessMin)# 生成个体
gen_size = 5
toolbox = base.Toolbox()
toolbox.register('Attr_float',np.random.rand)
toolbox.register('Individual',tools.initRepeat,creator.Individual,toolbox.Attr_float,n = gen_size)# 生成初始族群
pop_size =10
toolbox.register('Population',tools.initRepeat,list,toolbox.Individual)
pop = toolbox.Population(n=pop_size)# 定义评价函数
def evaluate(individual):return sum(individual),     # 注意这个逗号,即使是单变量优化问题,也需要返回tuple# 评价初始族群
toolbox.register('Evaluate',evaluate)
fitnesses = map(toolbox.Evaluate,pop)
for ind,fit in zip(pop,fitnesses):# 适应度ind.fitness.values = fit# 选择方式1:锦标赛选择
toolbox.register('TourSel',tools.selTournament,tournsize=2)     # tournsize=2的锦标赛选择
selectedTour = toolbox.TourSel(pop,5)       # 重复选择5次
print('锦标赛选择结果:')
for ind in selectedTour:print(ind)print(ind.fitness.values)# 锦标赛选择结果:
# [0.5729872692894181, 0.008673765598957717, 0.6006883278136533, 0.36975231024932076, 0.19855155932776247]
# (1.7506532322791124,)
# [0.21388615180584047, 0.31945979630877375, 0.4338560359091559, 0.7876917252475398, 0.9495119641480025]
# (2.7044056734193127,)
# [0.7669843252601127, 0.13083426935753661, 0.0942547981612144, 0.23742334817419075, 0.47322101773875513]
# (1.7027177586918096,)
# [0.7839533597901636, 0.899141593580464, 0.7864007285990595, 0.5290679145037971, 0.17188869028685316]
# (3.1704522867603373,)

轮盘赌选择

import numpy as np
from scipy.stats import bernoulli
from deap import base,creator,tools# 定义问题
creator.create('FitnessMin',base.Fitness,weights=(-1.0,))    # 单目标优化,求最小值
creator.create('Individual',list,fitness=creator.FitnessMin)# 生成个体
gen_size = 5
toolbox = base.Toolbox()
toolbox.register('Attr_float',np.random.rand)
toolbox.register('Individual',tools.initRepeat,creator.Individual,toolbox.Attr_float,n = gen_size)# 生成初始族群
pop_size =10
toolbox.register('Population',tools.initRepeat,list,toolbox.Individual)
pop = toolbox.Population(n=pop_size)# 定义评价函数
def evaluate(individual):return sum(individual),     # 注意这个逗号,即使是单变量优化问题,也需要返回tuple# 评价初始族群
toolbox.register('Evaluate',evaluate)
fitnesses = map(toolbox.Evaluate,pop)
for ind,fit in zip(pop,fitnesses):# 适应度ind.fitness.values = fit# 选择方式2:轮盘赌选择
toolbox.register('RoulSel',tools.selRoulette)
selectedRoul = toolbox.RoulSel(pop,5)
print('轮盘赌选择结果:')
for ind in selectedRoul:print(ind)print(ind.fitness.values)   # 评价# 轮盘赌选择结果:
# [0.9550769988029374, 0.6578118916399777, 0.7848918026380387, 0.4753637629038301, 0.8646738654753418]
# (3.7378183214601255,)
# [0.029709984320678395, 0.6451635420509633, 0.97539125983733, 0.9888777564043769, 0.7875687869284083]
# (3.4267113295417566,)
# [0.32535329853320827, 0.6346170850171972, 0.1472596326968919, 0.6370886415454745, 0.4328503853543919]
# (2.1771690431471633,)
# [0.9550769988029374, 0.6578118916399777, 0.7848918026380387, 0.4753637629038301, 0.8646738654753418]
# (3.7378183214601255,)
# [0.09799494527494135, 0.6574255771977907, 0.3028956551261657, 0.6399829324763072, 0.8012790620839682]
# (2.499578172159173,)

随机普遍抽样

import numpy as np
from scipy.stats import bernoulli
from deap import base,creator,tools# 定义问题
creator.create('FitnessMin',base.Fitness,weights=(-1.0,))    # 单目标优化,求最小值
creator.create('Individual',list,fitness=creator.FitnessMin)# 生成个体
gen_size = 5
toolbox = base.Toolbox()
toolbox.register('Attr_float',np.random.rand)
toolbox.register('Individual',tools.initRepeat,creator.Individual,toolbox.Attr_float,n = gen_size)# 生成初始族群
pop_size =10
toolbox.register('Population',tools.initRepeat,list,toolbox.Individual)
pop = toolbox.Population(n=pop_size)# 定义评价函数
def evaluate(individual):return sum(individual),     # 注意这个逗号,即使是单变量优化问题,也需要返回tuple# 评价初始族群
toolbox.register('Evaluate',evaluate)
fitnesses = map(toolbox.Evaluate,pop)
for ind,fit in zip(pop,fitnesses):# 适应度ind.fitness.values = fit# 选择方式3:随机普遍抽样
toolbox.register('StoSel',tools.selStochasticUniversalSampling)
selectedSto = toolbox.StoSel(pop,5)
print('随机普遍抽样选择结果:')
for ind in selectedSto:print(ind)print(ind.fitness.values)   # 评价# 随机普遍抽样选择结果:
# [0.11743447300592158, 0.007155258960584665, 0.5496123423851749, 0.8194743589767185, 0.2663407793385737]
# (1.7600172126669733,)
# [0.4022002953002052, 0.5700670841477128, 0.6810491418747713, 0.30968413662931094, 0.6146393712698289]
# (2.577640029221829,)
# [0.23895973414426974, 0.9668862753877311, 0.6281296472666623, 0.9976928770103559, 0.03208842104803378]
# (2.8637569548570525,)
# [0.42934155709721167, 0.6651561511010192, 0.9919663951989708, 0.743237320593636, 0.9741755416189538]
# (3.803876965609791,)
# [0.8767025943724408, 0.7220956393470699, 0.9783334331656188, 0.7777399869822683, 0.6733775135894544]
# (4.028249167456853,)

四.交叉

1.DEAP内置的交叉操作(crossover)操作

2.常用交叉操作介绍

单点交叉

deap.tools.cxOnePoint(ind1, ind2)

最简单的交叉方式,选择一个切口,将两条基因切开之后,交换尾部基因段。尽管该方法非常简单,但是多篇文章指出,该算法在各种实验中性能都被其他交叉算法吊打,因此算是一种不建议使用的loser algorithm

两点交叉

deap.tools.cxTwoPoint(ind1, ind2)

用两个点切开基因后,交换切出来的基因段

均匀交叉

deap.tools.cxUniform(ind1, ind2, indpb)

指定一个变异几率,两父代中的每一个基因都以该几率交叉

部分匹配交叉

deap.tools.cxPartialyMatched(ind1, ind2)

部分匹配交叉主要用于序列编码的个体,进行部分匹配交叉包括三个步骤:
首先,选择父辈1的一段基因,复制到子代中;
其次,查找父辈2中同位置的基因段,选择没有被复制的基因,建立一个映射关系;
最后,进行冲突检查,如果有基因冲突,则通过建立的映射变换为无冲突的基因,保证形成的一对子代基因无冲突。

当解决路径规划问题时,如果最优sub-subrouine越长,PMX交叉后就越难在子代中保留。
有序交叉

deap.tools.cxOrdered(ind1, ind2)


混合交叉

deap.tools.cxBlend(ind1, ind2, alpha)


模拟二值交叉

deap.tools.cxSimulatedBinary(ind1, ind2, eta)

SBX是在1995年由Deb和Agrawal提出来的。二进制编码有只能进行离散搜索,Hamming cliff等问题,而实数编码尽管能在连续域上操作,但是搜索能力较弱(此处搜索能力定义为给定一对父辈,产生任意子代的几率,可以用扩散系数表征)。
模拟二值交叉试图综合二者的优势,在实数编码上模拟二进制编码的搜索特点。

参数ηc越大,产生的子代与父代越接近;该参数越小,产生的子代越可能与父代差距较大。

作者认为SBX在较难的测试中,表现比BLX-0.5要更优,尤其在多局部最优问题中表现出色。更具体的测试可以参见原文。

混乱单点交叉

deap.tools.cxMessyOnePoint(ind1, ind2)

遗传算法中的基因都是如此有序:长短一致,编码方式整整齐齐,反而在自然界中这样的规律并不多见。基于这种情况,研究人员将交叉操作拆分为cut与splice,混乱单点交叉与一般的单点交叉最大的不同在于序列长度不会保持

3.交叉操作代码示例

官方提示最好不要直接用父代进行交叉,因此,有些交叉算法是in-place运算的,因此,最好先复制,再进行交叉。
单点交叉

import random
from deap import creator,base,tools# 定义问题
creator.create('FitnessMin',base.Fitness,weights = (-1.0,))     # 单变量优化
creator.create('Individual',list,fitness=creator.FitnessMin)# 生成序列个体
gene_size = 10
toolbox = base.Toolbox()
toolbox.register('Indices',random.sample,range(gene_size),gene_size)
toolbox.register('Individual',tools.initIterate,creator.Individual,toolbox.Indices)# 创建两个序列编码个体
ind1,ind2 = [toolbox.Individual() for _ in range(2)]
print(ind1,'\n',ind2)
# [7, 9, 4, 1, 8, 5, 0, 6, 3, 2]
#  [3, 0, 8, 7, 4, 9, 6, 1, 5, 2]# 单点交叉
child1,child2 = [toolbox.clone(ind) for ind in (ind1,ind2)]
tools.cxOnePoint(child1,child2)
print(child1,'\n',child2)
# [7, 9, 8, 7, 4, 9, 6, 1, 5, 2]
#  [3, 0, 4, 1, 8, 5, 0, 6, 3, 2]
# 可以看到从第三位开始被切开并交换

两点交叉

import random
from deap import creator,base,tools# 定义问题
creator.create('FitnessMin',base.Fitness,weights = (-1.0,))     # 单变量优化
creator.create('Individual',list,fitness=creator.FitnessMin)# 生成序列个体
gene_size = 10
toolbox = base.Toolbox()
toolbox.register('Indices',random.sample,range(gene_size),gene_size)
toolbox.register('Individual',tools.initIterate,creator.Individual,toolbox.Indices)# 创建两个序列编码个体
ind1,ind2 = [toolbox.Individual() for _ in range(2)]
print(ind1,'\n',ind2)# [2, 7, 5, 8, 4, 0, 1, 9, 3, 6]
#  [6, 5, 7, 2, 0, 9, 1, 4, 8, 3]# 两点交叉
child1,child2 = [toolbox.clone(ind) for ind in (ind1,ind2)]
tools.cxTwoPoint(child1,child2)
print(child1,'\n',child2)
# [2, 7, 7, 8, 4, 0, 1, 9, 3, 6]
#  [6, 5, 5, 2, 0, 9, 1, 4, 8, 3]
# 可以看到基因段[7]与基因段[5]互换了

均匀交叉

mport random
from deap import creator,base,tools# 定义问题
creator.create('FitnessMin',base.Fitness,weights = (-1.0,))     # 单变量优化
creator.create('Individual',list,fitness=creator.FitnessMin)# 生成序列个体
gene_size = 10
toolbox = base.Toolbox()
toolbox.register('Indices',random.sample,range(gene_size),gene_size)
toolbox.register('Individual',tools.initIterate,creator.Individual,toolbox.Indices)# 创建两个序列编码个体
ind1,ind2 = [toolbox.Individual() for _ in range(2)]
print(ind1,'\n',ind2)# [4, 3, 1, 0, 9, 2, 7, 5, 8, 6]
#  [9, 4, 2, 8, 3, 5, 7, 6, 0, 1]# 均匀交叉
child1,child2 = [toolbox.clone(ind) for ind in (ind1,ind2)]
tools.cxUniform(child1,child2,0.5)
print(child1,'\n',child2)# [4, 3, 2, 8, 3, 2, 7, 5, 8, 1]
#  [9, 4, 1, 0, 9, 5, 7, 6, 0, 6]

部分匹配交叉

import random
from deap import creator,base,tools# 定义问题
creator.create('FitnessMin',base.Fitness,weights = (-1.0,))     # 单变量优化
creator.create('Individual',list,fitness=creator.FitnessMin)# 生成序列个体
gene_size = 10
toolbox = base.Toolbox()
toolbox.register('Indices',random.sample,range(gene_size),gene_size)
toolbox.register('Individual',tools.initIterate,creator.Individual,toolbox.Indices)# 创建两个序列编码个体
ind1,ind2 = [toolbox.Individual() for _ in range(2)]
print(ind1,'\n',ind2)# [6, 9, 3, 7, 2, 5, 1, 8, 4, 0]
#  [4, 9, 8, 6, 2, 7, 3, 1, 0, 5]# 部分匹配交叉
child1,child2 = [toolbox.clone(ind) for ind in (ind1,ind2)]
tools.cxPartialyMatched(child1,child2)
print(child1,'\n',child2)
# [7, 9, 3, 6, 2, 5, 1, 8, 4, 0]
#  [4, 9, 8, 7, 2, 6, 3, 1, 0, 5]
# 与之前的交叉算子明显不同,这里的每个序列都没有冲突

有序交叉

import random
from deap import creator,base,tools# 定义问题
creator.create('FitnessMin',base.Fitness,weights = (-1.0,))     # 单变量优化
creator.create('Individual',list,fitness=creator.FitnessMin)# 生成序列个体
gene_size = 10
toolbox = base.Toolbox()
toolbox.register('Indices',random.sample,range(gene_size),gene_size)
toolbox.register('Individual',tools.initIterate,creator.Individual,toolbox.Indices)# 创建两个序列编码个体
ind1,ind2 = [toolbox.Individual() for _ in range(2)]
print(ind1,'\n',ind2)# [7, 6, 8, 4, 1, 5, 9, 2, 0, 3]
#  [5, 9, 3, 1, 0, 2, 7, 4, 8, 6]# 有序交叉
child1,child2 = [toolbox.clone(ind) for ind in (ind1,ind2)]
tools.cxOrdered(child1,child2)
print(child1,'\n',child2)
# [6, 8, 1, 5, 9, 2, 7, 4, 0, 3]
#  [5, 3, 1, 0, 7, 4, 9, 2, 8, 6]

混乱单点交叉

import random
from deap import creator,base,tools# 定义问题
creator.create('FitnessMin',base.Fitness,weights = (-1.0,))     # 单变量优化
creator.create('Individual',list,fitness=creator.FitnessMin)# 生成序列个体
gene_size = 10
toolbox = base.Toolbox()
toolbox.register('Indices',random.sample,range(gene_size),gene_size)
toolbox.register('Individual',tools.initIterate,creator.Individual,toolbox.Indices)# 创建两个序列编码个体
ind1,ind2 = [toolbox.Individual() for _ in range(2)]
print(ind1,'\n',ind2)# [9, 1, 3, 7, 6, 2, 0, 5, 8, 4]
#  [7, 5, 9, 0, 3, 8, 4, 1, 6, 2]# 混乱单点交叉
child1,child2 = [toolbox.clone(ind) for ind in (ind1,ind2)]
tools.cxMessyOnePoint(child1,child2)
print(child1,'\n',child2)
# [9, 1, 3, 7, 6, 2, 0, 9, 0, 3, 8, 4, 1, 6, 2]
#  [7, 5, 5, 8, 4]
# 注意个体序列长度的改变

五.变异

1.DEAP内置的突变(Mutation)操作

2.常用突变介绍

高斯突变

tools.mutGaussian(individual, mu, sigma, indpb)

对个体序列中的每一个基因按概率变异,变异后的值为按均值为u,方差为σ的高斯分布选取的一个随机数。如果不希望均值发生变化,则应该将u设为0
乱序突变

tools.mutShuffleIndexes(individual, indpb)

将个体序列打乱顺序,每个基因位置变动的几率由indup给出
位翻转突变

tools.mutFlipBit(individual, indpb)

对个体中的每一个基因按给定对变异概率取非
有界多项式突变

tools.mutPolynomialBounded(individual, eta, low, up, indpb)


均匀整数突变

tools.mutUniformInt(individual, low, up, indpb)

对序列中的每一位按概率变异,变异后的值为[low,up]中按均匀分布随机选取的一个整数。

3.突变操作代码示例

如果想要保留父代作为参照,那么最好先复制,然后再进行变异

import random
from deap import creator,base,toolsrandom.seed(42)     # 保证结果可复现
# 定义问题
creator.create('FitnessMin',base.Fitness,weights=(-1.0,))
creator.create('Individual',list,fitness = creator.FitnessMin)# 创建一个实数编码个体
gene_size = 5
toolbox = base.Toolbox()
toolbox.register('Attr_float',random.random)    # random.ramdom = np.random.rand
toolbox.register('Individual',tools.initRepeat,creator.Individual,toolbox.Attr_float,n = gene_size)ind = toolbox.Individual()
print(ind)
# [0.6394267984578837, 0.025010755222666936, 0.27502931836911926, 0.22321073814882275, 0.7364712141640124]# 高斯突变
mutant = toolbox.clone(ind)
tools.mutGaussian(mutant,3,0.1,1)
print(mutant)
# [3.672658632864655, 2.99827700737295, 3.2982590920597916, 3.339566606808737, 3.6626390539295306]
# 当均值给到3之后,变异形成的个体均值从0.5也增加大了3附近# 乱序突变
mutant = toolbox.clone(ind)
tools.mutShuffleIndexes(mutant,0.5)
print(mutant)
# [0.22321073814882275, 0.7364712141640124, 0.025010755222666936, 0.6394267984578837, 0.27502931836911926]# 有界多项式突变
mutant = toolbox.clone(ind)
tools.mutPolynomialBounded(mutant,20,0,1,0.5)
print(mutant)
# [0.674443861742489, 0.020055418656044655, 0.2573977358171454, 0.11555018832942898, 0.6725269223692601]# 均匀整数突变
mutant = toolbox.clone(ind)
tools.mutUniformInt(mutant,1,5,0.5)
print(mutant)
# [0.6394267984578837, 3, 0.27502931836911926, 0.22321073814882275, 0.7364712141640124]
# 可以看出在第二个位置生成了整数3

六.环境选择

环境选择也就是重插入,在选择、交叉和突变之后,得到的育种后代族群规模与父代相比可能增加或减少。为保持种群规模,需要将育种后代插入到父代中,替换父代种群的一部分个体,或者丢弃一部分育种个体。

重插入分为全局重插入(Global reinsertion) 和本地重插入(Local reinsertion)两种,后者只有在使用含有本地邻域的算法时使用。
常用的全局重插入操作有以下四种:
1.完全重插入(Pure reinsertion):产生与父代个体数量相当的配种个体,直接用配种个体生成新一代族群。
2.均匀重插入(Uniform reinsertion):产生比父代个体少的配种个体,用配种个体随机均匀地替换父代个体。
3.精英重插入(Elitist reinsertion):产生比父代个体少的配种个体,选取配种后代中适应度最好的一些个体,插入父代中,取代适应度较低的父代个体。
4.精英保留重插入(Fitness-based reinsertion):产生比父代个体多的配种个体,选取其中适应度最大的配种个体形成新一代族群

通常来说,后两种方式由于精英保留的缘故,收敛速度更快,因此,比较推荐
DEAP中没有设定专门的reinsertion操作,可以用选择操作中的selBest,selWorst,selRandom来对育种族群和父代族群进行操作。

基于DEAP库的python进化算法-2.进化算法各元素的DEAP实现相关推荐

  1. 基于Pyinstaller库将Python项目包括 图片打包exe方法,本人已经实践多次

    基于Pyinstaller库将Python项目包括 图片打包exe方法,本人已经实践多次 文章目录 基于Pyinstaller库将Python项目包括 图片打包exe方法,本人已经实践多次 一.前言 ...

  2. 遗传算法 python 简书_基于DEAP库的Python进化算法从入门到入土—(二)简单遗传算法实现...

    前言 在上一篇中,我们已经介绍了如何在DEAP中实现进化算法的基本操作,在这一篇中我们试图将各个操作组装起来,用进化算法解决一个简单的一元函数寻优问题. 进化算法实例 - 一元函数寻优 问题描述与分析 ...

  3. python路线寻优_基于DEAP库的Python进化算法从入门到入土 --(四)遗传算法的改进...

    前言 前面一节我们尝试了用GA求解TSP问题,简单遗传算法总是不能很好收敛到一个较优的解,在用时和求解精度上都被贪心算法吊打.在末尾我们总结了三个可能的改进方向,这次我们想要沿着这三个方向试着改进简单 ...

  4. 基于DEAP库的Python进化算法

    https://www.jianshu.com/p/8fa044ed9267 http://geatpy.com/index.php/category/geatpy_tutorials/

  5. GEAP 遗传算法/遗传编程 genetic programming + python(deap库)实现

    文章目录 前言 1.优化问题的定义 单目标优化 多目标优化 2.个体编码 实数编码 二进制编码 序列编码(Permutation encoding) 粒子(Particles) 3 初始种群建立 一般 ...

  6. 进化算法及Python实现(使用DEAP库)

    目录 进化算法介绍 算法优点 算法缺点 DEAP库介绍 使用DEAP实现EA 进化算法介绍 进化算法(也叫演化算法,Evolutionary Algorithms)包括遗传算法(Genetic Alg ...

  7. python分类算法的应用_Python基于sklearn库的分类算法简单应用示例

    Python基于sklearn库的分类算法简单应用示例 来源:中文源码网    浏览: 次    日期:2018年9月2日 [下载文档:  Python基于sklearn库的分类算法简单应用示例.tx ...

  8. 神经进化算法——利用NEAT算法解决迷宫导航问题(基于NEAT-Python)

    神经进化算法--利用NEAT算法解决迷宫导航问题(基于NEAT-Python) 迷宫导航问题 迷宫环境模拟 迷宫导航智能体 迷宫环境实现 传感器数据生成 导航智能体 智能体位置更新 智能体记录存储 智 ...

  9. python加密库_python基于pyDes库实现des加密的方法

    本文实例讲述了python基于pyDes库实现des加密的方法.分享给大家供大家参考,具体如下: 下载及简介地址:https://twhiteman.netfirms.com/des.html 如需要 ...

  10. 基于Python实现并测试Modularity算法

    实现并测试Modularity算法 一.问题简述 1.1 社区发现问题 社区发现问题(Community Detection)用于解决网络中的聚类问题,从网络中发现社区.网络中的社区是一个内部节点联系 ...

最新文章

  1. 我在想,技术博不能荒废
  2. linux script 命令
  3. vue中的if判断和for循环语句
  4. 前端开发中的一些js小技巧
  5. 【牛客 - 331J】炫酷数学(打表猜结论,按位枚举证明)
  6. SVN Cleanup失败解决方法
  7. 最新的 iOS 申请证书与发布流程
  8. Understanding Bootstrap Of Oracle Database
  9. Vue集成微信开发趟坑:公众号以及JSSDK相关
  10. Python的张量运算
  11. java自行车租凭系统项目包_基于java的校园自行车租用管理系统的设计及实现终极版.pdf...
  12. Android studio 制作一个app实现简单功能
  13. Docker进阶学习(容器数据卷、安装Mysql、DockerFile )
  14. tv 斐讯n1原生android_斐讯T1刷原生安卓TV
  15. 贵州中进大宗商品交易中心促进产销 打造优质平台
  16. 【cocos2d游戏开发实战】一款射击类小游戏《Zombie Age》的开发(一)
  17. 【转】我们应该如何去理解数学中的自然底数e
  18. 物联网行业解决方案之智慧畜牧
  19. 在misc中涉及的二维码
  20. android上调试H5小工具

热门文章

  1. Oracle EBS之把自定义concurrent加入Pick Release Document Set(All Pick Release Documents)的几个注意点...
  2. Sueetie源代码发布【 推荐 】
  3. Winform--处理MDI父窗体与子窗体的交互
  4. SQL SERVER 2005 数据挖掘与商业智能完全解决方案---学习笔记(一)
  5. 浅谈前后端分离与实践 之 nodejs 中间层服务
  6. java day38【Servlet 、HTTP协议 、Request】
  7. vue项目 拷到别的电脑应该怎吗再次重新运行
  8. HDU3709 Balanced Number
  9. mysql 的命令行操作
  10. SQL Server里的自旋锁介绍