本节将将在初始化的基础上,进一步说明操作与算法。
toolbox(base.Toolbox())是包含所有进化操作的工具箱,从目标初始化到适应度计算。它允许在每个算法中实现简单的构造。toolbox基本上由两种方法组成,register()和unregister(),这两种函数是用来添加和移除工具的。
需要区别Toolbox和Tools,前者包含后者关系,Tools更加纯粹的指向进化工具,如Initialization、Crossover、Mutation、Selection、Migration等等,具体查看官方教程。
fitnesses = list(map(toolbox.evaluate, pop))
for ind, fit in zip(pop, fitnesses):
ind.fitness.values = fit
toolbox.register('population', tools.initRepeat,list, toolbox.individual)
pop = toolbox.population(n = 30)
NGEN = 100 #ITERATION NUMBER
CXPB = 0.1 #CROSSOVER RATE
MUPB = 0.1 #MUTATION RATE
for i in range(NGEN):
#selection
offspring = toolbox.select(pop, len(pop)) #select len(pop) individuals from pop
#clone the selected individuals
offspring = list(map(toolbox.clone, offspring))
#crossover
for child1, child2 in zip(offspring[::2], offspring[1::2]):
if random.random() < CXPB:
toolbox.mate(child1, child2)
del child1.fitness.values
del child2.fitness.values
#mutation
for mutant in offspring:
if random.random() < MUPB:
toolbox.mutate(mutant)
del mutant.fitness.values
#evaluate the individuals with an invalid fitness
invalid_ind = [ind for ind in offspring if not ind.fitness.valid]
fitness = toolbox.map(toolbox.evaluate, invalid_ind)
for ind, fit in zip(invalid_ind, fitness):
ind.fitness.values = fit
#the population is entirely replaced by offspring
pop[:] = offspring
工具装饰是一个很强力的特征,它可以帮助你在演化过程中去精确地对算法和操作进行控制。一个装饰是指将函数进行包装,这叫做在真实的函数被调用前后做一些初始化和终止工作。例如,在一个有限的区域内,一种应用装饰符的方法是在变异和交叉的过程中保证个体不会越界。下面的定义就是检查是否有个体越界,装饰符是通过三个函数定义的,为了接收最小值和最大值。当变异或者交叉被调用时,边界将会检查它们的运算结果。
def checkBounds(min, max):
def decorator(func):
def wrapper(*args, **kargs):
offspring = func(*args, **kargs)
for child in offspring:
for i in xrange(len(child)):
if child[i] > max:
child[i] = max
elif child[i] < min:
child[i] = min
return offspring
return wrapper
return decorator
toolbox.register("mate", tools.cxBlend, alpha=0.2)
toolbox.register("mutate", tools.mutGaussian, mu=0, sigma=2)
toolbox.decorate("mate", checkBounds(MIN, MAX))
toolbox.decorate("mutate", checkBounds(MIN, MAX))
变化允许建立简单的算法,使用预定义好的小模块。为了使用变化,toolbox一定会建立一个包含所需运算符的集合。例如,在最近展示的完整算法案例中,交叉和变异运算在varAnd()中被重新整合。这个函数要求toolbox包含mate()和mutate()函数,这种变化可以用来简化算法,就像下面这样
from deap import algorithms
for g in range(NGEN):
# Select and clone the next generation individuals
offspring = map(toolbox.clone, toolbox.select(pop, len(pop)))
# Apply crossover and mutation on the offspring
offspring = algorithms.varAnd(offspring, toolbox, CXPB, MUPB)
# Evaluate the individuals with an invalid fitness
invalid_ind = [ind for ind in offspring if not ind.fitness.valid]
fitnesses = toolbox.map(toolbox.evaluate, invalid_ind)
for ind, fit in zip(invalid_ind, fitnesses):
ind.fitness.values = fit
# The population is entirely replaced by the offspring
pop[:] = offspring
穿插讲解Variations
Variations变体是算法的较小部分,可以单独用于构建更复杂的算法。
主要包含varAnd、varOr
algorithms.
varAnd
(population, toolbox, cxpb, mutpb)---函数的参数被写死了
进化算法的一部分,只应用变异部分(交叉和变异)。修改后的个体的适应度无效。个体被克隆,因此返回的种群独立于输入种群。
Parameters: |
|
---|---|
Returns: | A list of varied individuals that are independent of their parents. |
这种变异被命名为And,因为它需要在个体上同时应用交叉和突变。注意,这两种算子都不是系统应用的,产生的个体可以根据给定的概率从仅交叉、仅突变、交叉和突变以及繁殖中生成。两种概率都应在[0,1]中。
algorithms.
varOr
(population, toolbox, lambda_, cxpb, mutpb)
Parameters: |
|
---|---|
Returns: | The final population. |
变化如下。在每次lambda_迭代中,它从三个操作中选择一个;交叉、突变或繁殖。在交叉的情况下,从亲本群体Pp中随机选择两个个体,使用toolbox.clone()方法克隆这些个体,然后使用toolbox.mate()方法交配。只有第一个孩子被附加到后代群体Po,第二个孩子被丢弃。在突变的情况下,从Pp中随机选择一个个体,然后使用toolbox.mutate()方法对其进行克隆和突变。产生的突变体附加在Po上。在繁殖的情况下,从Pp中随机选择一个个体,克隆并附加到Po中。
这种变异被命名为Or,因为后代永远不会同时来自交叉和突变操作。两种概率之和应为[0,1],再现概率为1-cxpb-mutpb。
有许多种可以在algorithm模块中使用的算法,它们十分简单并且可以反映演化算法的基本类型。这些算法使用Toolbox作为定义好的内容。一旦toolbox被设定完成,它们将会去调用这些算法。简单的演化算法需要五个参数,种群、toolbox、交叉率、变异率和种群迭代次数。
举例如下
from deap import algorithms
algorithms.eaSimple(pop, toolbox, cxpb=0.5, mutpb=0.2, ngen=50)
算法库中列举的算法包含:
1、deap.algorithms.
eaSimple
(population, toolbox, cxpb, mutpb, ngen[, stats, halloffame, verbose])
2、deap.algorithms.
eaMuPlusLambda
(population, toolbox, mu, lambda_, cxpb, mutpb, ngen[, stats, halloffame, verbose])
............///具体的内容,可以参考官方文档,不做展开了。