问题描述:列表中仅有0和1,求和最大的情况
import random
import numpy as np
from deap import base
from deap import creator
from deap import tools
from deap import algorithms
# 创建FitnessMax类, 继承base.Fitness, attribute为weights
creator.create("FitnessMax", base.Fitness, weights=(1.0,))
# Individual, 继承list, attribute为fitness
creator.create("Individual", list, fitness=creator.FitnessMax) # 定义个体类型
我们将使用的所有对象: 个体、种群以及所有函数、运算符和参数都将存储在一个名为“Toolbox”的DEAP container中。它包含两种添加和删除内容的方法: register()和unregister()
toolbox = base.Toolbox()
# attr_bool是函数random.randint(0,1)的别名
# 定义基因
toolbox.register("attr_bool", random.randint, 0, 1)
# individual是函数tools.initRepeat(creator.Individual, toolbox.attr_bool, 100)的别名
# tools.initRepeat(container, func, n)由func中的数据填充的容器实例
# container – 用于放入func生成的数据的类型
# func – 将被调用n次以填充container的函数
# n – 重复func的次数
# 创建个体,编码长度为100
toolbox.register("individual", tools.initRepeat, creator.Individual, toolbox.attr_bool, 100)
# 创建种群
toolbox.register("population", tools.initRepeat, list, toolbox.individual)
# 返回值的长度必须等于目标数(权重个数)。
def evalOneMax(individual):
# 返回的是个元祖,注意,
return sum(individual),
toolbox.register("evaluate", evalOneMax)
# 两点交叉,编码串中随机设置两段交叉点进行基因交换
toolbox.register("mate", tools.cxTwoPoint)
# 变异,用于bool值(二进制类型)的变异,indpb为变异概率
toolbox.register("mutate", tools.mutFlipBit, indpb=0.05)
# 选择,先随机选择tournsize个个体,然后根据个体的fitness,选择最佳个体,重复k次
toolbox.register("select", tools.selTournament, tournsize=3)
def main():
# 创建300个大小的种群,300*100(个体编码长度)
pop = toolbox.population(n=300)
# CXPB: 两个个体之间交叉的概率
# MUTPB: 个体的变异概率
CXPB, MUTPB = 0.5, 0.2
print("Start of evolution")
# 评价整个种群
fitnesses = list(map(toolbox.evaluate, pop))
for ind, fit in zip(pop, fitnesses):
ind.fitness.values = fit
# 获取整个种群的适应度
fits = [ind.fitness.values[0] for ind in pop]
# 当前种群的代数
g = 0
# 开始进化
while max(fits) < 100 and g < 1000:
# 下一代
g += 1
print("-- Generation %i --" % g)
# 下一代种群选择
offspring = toolbox.select(pop, len(pop))
# 克隆选择的种群,确保每个个体为独立的实例,而不是引用
offspring = list(map(toolbox.clone, offspring))
# 交叉,inplace修改
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
# 变异,inplace修改
for mutant in offspring:
if random.random() < MUTPB:
toolbox.mutate(mutant)
del mutant.fitness.values
# 对新的子代进行评估
invalid_ind = [ind for ind in offspring if not ind.fitness.valid]
fitnesses = map(toolbox.evaluate, invalid_ind)
for ind, fit in zip(invalid_ind, fitnesses):
ind.fitness.values = fit
# 下一代替代父代
pop[:] = offspring
# 种群适应度
fits = [ind.fitness.values[0] for ind in pop]
length = len(pop)
mean = sum(fits) / length
sum2 = sum(x*x for x in fits)
std = abs(sum2 / length - mean**2)**0.5
# 输出当前种群状态
print(" Min %s" % min(fits))
print(" Max %s" % max(fits))
print(" Avg %s" % mean)
print(" Std %s" % std)
main()
DEAP中预置的简单进化算法deap.algorithms.eaSimple
流程描述如下:
toolbox.evaluate
评价族群toolbox.select
选择与父代相同个数的育种个体toolbox.mate
进行配种,并用生成的两个子代替换对应父代toolbox.mutate
进行变异,用变异后的子代替换对应父代需要注意的是在这个过程中,生成子代有四种情况:受到配种影响;受到变异影响;既受到配种也受到变异影响;既不受配种影响也不受变异影响。
对应的伪代码可以表述为:
evaluate(population)
for g in range(ngen):
population = select(population, len(population))
offspring = varAnd(population, toolbox, cxpb, mutpb)
evaluate(offspring)
population = offspring
def main():
pop = toolbox.population(n=300)
# 用于trace最佳样本
hof = tools.HallOfFame(1)
# 对每次迭代时进行种群效果计算
stats = tools.Statistics(lambda ind: ind.fitness.values)
stats.register("avg", numpy.mean)
stats.register("std", numpy.std)
stats.register("min", numpy.min)
stats.register("max", numpy.max)
# 简单进化算法, ngen代数
pop, log = algorithms.eaSimple(pop, toolbox, cxpb=0.5, mutpb=0.2, ngen=40,
stats=stats, halloffame=hof, verbose=True)
return pop, log
pop, log, hof = main()
'''第一处修改'''
creator.create("Individual", np.ndarray, fitness=creator.FitnessMax) # 定义个体类型
# 自定义numpy情况下的基因交叉操作
def cxTwoPointCopy(ind1, ind2):
"""Execute a two points crossover with copy on the input individuals. The
copy is required because the slicing in numpy returns a view of the data,
which leads to a self overwritting in the swap operation. It prevents
::
>>> import numpy
>>> a = numpy.array((1,2,3,4))
>>> b = numpy.array((5,6,7,8))
>>> a[1:3], b[1:3] = b[1:3], a[1:3]
>>> print(a)
[1 6 7 4]
>>> print(b)
[5 6 7 8]
"""
size = len(ind1)
cxpoint1 = random.randint(1, size)
cxpoint2 = random.randint(1, size - 1)
if cxpoint2 >= cxpoint1:
cxpoint2 += 1
else: # Swap the two cx points
cxpoint1, cxpoint2 = cxpoint2, cxpoint1
# 注意copy操作
ind1[cxpoint1:cxpoint2], ind2[cxpoint1:cxpoint2] \
= ind2[cxpoint1:cxpoint2].copy(), ind1[cxpoint1:cxpoint2].copy()
return ind1, ind2
'''第二处修改'''
toolbox.register("mate", cxTwoPointCopy)
def main():
'''第三处修改,增加similar的定义'''
hof = tools.HallOfFame(1, similar=numpy.array_equal)
import random
import numpy as np
from deap import base
from deap import creator
from deap import tools
from deap import algorithms
IND_INIT_SIZE = 5 # 初始化物品数
MAX_ITEM = 50 # 最大可选物品数
MAX_WEIGHT = 50 # 最大背包承重
NBR_ITEMS = 20 # 物品数
# 保证可复现性
random.seed(64)
# 创建随机项字典,用来表示NBR_ITEMS个物品的重量及价值
items = {}
for i in range(NBR_ITEMS):
items[i] = (random.randint(1, 10), random.uniform(0, 100))
# 物品重量最小化, 物品价值最大化, 多目标优化问题 — 物品重量尽可能小,价值尽可能大
creator.create("Fitness", base.Fitness, weights=(-1.0, 1.0))
# 继承自set,保证每个物品只取一次
creator.create("Individual", set, fitness=creator.Fitness)
toolbox = base.Toolbox()
# 基因取值-[0,NBR_ITEMS)表示各个物品的index
toolbox.register("attr_item", random.randrange, NBR_ITEMS)
# 个体, 基因长度IND_INIT_SIZE, 代表选IND_INIT_SIZE个物品
toolbox.register("individual", tools.initRepeat, creator.Individual, toolbox.attr_item, IND_INIT_SIZE)
# 种群
toolbox.register("population", tools.initRepeat, list, toolbox.individual)
返回weight, value代表两个目标的当前适应度值
def evalKnapsack(individual):
weight = 0.0
value = 0.0
for item in individual:
weight += items[item][0]
value += items[item][1]
if len(individual) > MAX_ITEM or weight > MAX_WEIGHT:
return 10000, 0 # 行李超重
return weight, value
def cxSet(ind1, ind2):
"""两个set的交叉方法"""
temp = set(ind1) # Used in order to keep type
ind1 &= ind2 # 求 交集
ind2 ^= temp # 求 并集-交集
return ind1, ind2
def mutSet(individual):
"""变异情况为增加或减少物品数"""
if random.random() < 0.5:
if len(individual) > 0: # We cannot pop from an empty set
# set不支持index操作,因此不能随机选择,要进行类型转换
individual.remove(random.choice(sorted(tuple(individual))))
else:
individual.add(random.randrange(NBR_ITEMS))
return individual,
toolbox.register("evaluate", evalKnapsack)
toolbox.register("mate", cxSet)
toolbox.register("mutate", mutSet)
# 这是一个多目标问题,采用NSGA-II选择方案,在多目标情况下选择合适较优的种群
toolbox.register("select", tools.selNSGA2)
def main():
random.seed(64)
NGEN = 50 # 进化代数
MU = 50 # 种群数,每次保留的种群数
LAMBDA = 100 # 每一代生成的子代数
CXPB = 0.7 # 交叉率
MUTPB = 0.2 # 变异率
pop = toolbox.population(n=MU)
hof = tools.ParetoFront()
stats = tools.Statistics(lambda ind: ind.fitness.values)
stats.register("avg", np.mean, axis=0)
stats.register("std", np.std, axis=0)
stats.register("min", np.min, axis=0)
stats.register("max", np.max, axis=0)
# 每次生成100子代,在父代+子代中选择MU个作为子代
# mu+lambda进化算法,该算法中子代不会同时受到变异和配种影响
algorithms.eaMuPlusLambda(pop, toolbox, MU, LAMBDA, CXPB, MUTPB, NGEN, stats,
halloffame=hof)
# pop, log = algorithms.eaSimple(pop, toolbox, cxpb=CXPB, mutpb=MUTPB, ngen=NGEN,
# stats=stats, halloffame=hof, verbose=True)
return pop, stats, hof
pop, stats, hof = main()
Deap中的 ( μ + λ ) (\mu+\lambda) (μ+λ) 进化算法deap.algorithms.eaMuPlusLambda
该算法的流程如下:
toolbox.evaluate
评价族群toolbox.mate
进行配种,将生成的第一个子代加入到后代列表中,第二个子代丢弃;如果选择到mutation,用工具箱中注册的toolbox.mutate
进行变异,将变异后的子代加入到后代列表中;如果选择到reproduction,随机选择一个个体,将其复制加入到后代列表中toolbox.select
,在父代+子代中选择给定数量的个体作为子代注意在这个子代生成的过程中,子代不会同时受到变异和配种影响。
对应的伪代码可以表述为:
evaluate(population)
for g in range(ngen):
offspring = varOr(population, toolbox, lambda_, cxpb, mutpb)
evaluate(offspring)
population = select(population + offspring, mu)
Deap中的 ( μ , λ ) (\mu,\lambda) (μ,λ) 进化算法deap.algorithms.eaMuCommaLambda
该算法的流程和 ( μ + λ ) (\mu+\lambda) (μ+λ)基本相同,唯一的区别在于生成子代族群时,只在产生的子代中选择,而丢弃所有父代。
对应的伪代码可以表述为
evaluate(population)
for g in range(ngen):
offspring = varOr(population, toolbox, lambda_, cxpb, mutpb)
evaluate(offspring)
population = select(offspring, mu)