python 遗传算法_遗传算法(Python) #5 用DEAP框架解决OneMax问题

遗传算法系列的第三期介绍了如何不用任何框架从零开始解决OneMax问题,第四期介绍了DEAP框架的基本用法。若读者对下文中定义或术语不熟悉,可以查看本系列的前几篇文章。本期文章将介绍如何使用DEAP解决OneMax问题。

1.OneMax问题(OneMax problem)

OneMax问题是遗传算法的入门问题,其内容是:如何使一段长度固定的二进制字符串所有位置上数字之和最大。

让我们用一个长度为5的二进制字符串为例:

  • 10010 -> 和为2
  • 00111 -> 和为3
  • 11111 -> 和为5(最大值)

对一般人,显而易见,当所有位数都为1时,该字符串的和最大,但在我们用遗传算法解决该问题时,算法本身并不具备这样的知识。

2.问题的解决思路

首先,我们得把这个问题转换成一个遗传算法问题,即:我们得定义个体、种群,选择、杂交、突变方法、适应度函数等。假设有一个长度为100的字符串,我们可以做出以下定义:

  • 个体:个体即为问题的解,这个问题中个体可以直观的定义为一个长度为100列表(List),列表上每个元素为0或1.
  • 种群:种群即所有个体的合集,我们可以把种群定义为所有个体组成的列表。
  • 选择:使用锦标赛法(Tournament Selection)
  • 杂交:使用单点杂交法(Singe-Point Crossover)
  • 突变:使用位翻转突变法(Flip Bit Mutation)
  • 适应度函数: 我们的目标是使字符串上所有数字之和最大,适应度函数可以直观的定义为列表中所有数字之和。

若对上述定义不太了解的,可以回看遗传算法系列的第二期。

3.用DEAP框架实现遗传算法

以下将分步骤解释每一部分的代码,完整代码在本文的最后可见。

3.1. 准备工作

# 1.load modulesfrom deap import base,creator,tools,algorithmsimport randomimport numpy as npimport matplotlib.pyplot as plttoolbox = base.Toolbox()

首先我们需要导入遗传算法所必须的模组:

  • base,creator,tools,algorithms: 这四个模组是DEAP框架内最常用的模组
  • random: 用以生成随机数
  • numpy:我们将用到 numpy 中的 mean 和 max 方程。
  • matplotlib: 用以绘图
  • toolbox:DEAP框架中的核心,当使用deap.algorithms时,我们需要把遗传算法的运算符存入toolbox内。 同时toolbox.register也是DEAP中最常用的方法。

3.2. 初始化算法参数

# 2.parameters:INDIVIDUAL_LENGTH = 100  # length of bit string to be optimizedPOPULATION_SIZE = 200P_CROSSOVER = 0.9  # probability for crossoverP_MUTATION = 0.1   # probability for mutating an individualMAX_GENERATIONS = 50random.seed(39)
  • INDIVIDUAL_LENGTH:个体的“长度”,即二进制字符串的长度
  • POPULATION_SIZE: 种群中个体的数目
  • P_CROSSOVER: 个体间交杂的概率
  • P_MUTATION: 个体突变的概率
  • MAX_GENERATIONS: 算法迭代次数上限
  • random.seed:为了保证每次运行的结果相同,设定了随机种子

3.3. 定义个体与种群

# 3.create individual and populationtoolbox.register("genBinary", random.randint, 0, 1) # 1creator.create("FitnessMax", base.Fitness, weights=(1.0,)) # 2creator.create("Individual", list, fitness=creator.FitnessMax) # 3toolbox.register("createIndividual", tools.initRepeat, creator.Individual, toolbox.genBinary, INDIVIDUAL_LENGTH) # 4toolbox.register("createPopulation", tools.initRepeat, list, toolbox.createIndividual) # 5
  1. 这一列定了genBinary方程:该函数可以随机生成0或1;通过toolbox.register()定义后,我们可以通过toolbox.genBinary()直接使用该函数。
  2. 因为在OneMax问题中,我们需要适应度的最大值,所以我们拓展base.Fitness类,并将拓展后的类命名为FitnessMax,并设定其权重为(1.0,),代表求最大值(在其他问题中,如果需要求最小值的,可以定义权重为(-1.0,))。
  • 在这里注意我们定义权重是(1.0,)而不是1.0,其原因是DEAP框架支持求多个目标的的最大/最小值,所以我们必须定义权重为元组(tuple)。
  • 当在其他问题中我们的适应度方程有多个目标:如当我们需要第一个目标最大,同时第二个目标最小,且第一个目标的重要性是第二个目标的两倍时,权重可以定义为:(1.0,-0.5)
  1. 创建Individual类,并让FitnessMax做为Individual的fitness特性(attribute)
  1. 定义createIndividual方程:该方程可以生成长度为INDIVIDUAL_LENGTH的列表,通过调用genBinary函数,列表内每个元素随机为0或1.
  1. 定义createPopulation方程:该方程可以生成长度待定的列表,列表中每个元素由createIndividual方程创建。
  • 注意createPopulation方程并没有定义列表的长度,这是因为toolbox.register中用到了functools.partial方程,尚未定义的参数会以*args或**kwargs的形式传递给tools.initRepeat方程。

如果读者对DEAP框架内的方程不太了解,看完上述解释后还是感觉五里雾中,建议查看本系列前两期文章,或者到DEAP官网上多了解下这些方程的定义。

3.4. 定义适应度函数

# 4. define evaluation functiontoolbox.register("evaluate", lambda ind: (sum(ind),))

在OneMax问题中,适应度函数即为个体(用二进制字符串表示)上所有数字之和,因此我们将适应度函数定义为(sum(ind),)。

在这里请特别注意

  • 因为DEAP框架支持有多个目标的适应度函数,所以我们必须把适应度函数的输出定义为元组。
  • evaluate是关键词,若要使用DEAP框架,必须使用evaluate这个单词来命名适应度函数。

3.5. 定义遗传算法运算符(选择,杂交,突变)

# 5. define operatorstoolbox.register("select", tools.selTournament, tournsize=2)toolbox.register("mate", tools.cxOnePoint)toolbox.register("mutate", tools.mutFlipBit, indpb=1.0/INDIVIDUAL_LENGTH)
  • select:锦标赛法作为选择运算符,tournsize表示锦标赛的大小
  • mate:单点杂交作为杂交运算符
  • mutate:多位翻转突变作为突变运算符,indpb表示了每一个位置上基因突变的概率。在本文中INDIVIDUAL_LENGTH默认为100, 即每个体格由一百个二进制字符组成,每个字符突变的概率为1%

请特别注意:

select, mate, mutate都是DEAP框架中的关键词,在定义运算符时,必须使用使用这几个单词。

3.6. 运行遗传算法

# Genetic Algorithm flow:def main():    # create population    population = toolbox.createPopulation(n=POPULATION_SIZE)    # initialize statistics    stats = tools.Statistics(lambda ind: ind.fitness.values)    stats.register("max", np.max)    stats.register("avg", np.mean)    # Genetic Algorithm    population, logbook = algorithms.eaSimple(population, toolbox, cxpb=P_CROSSOVER,     mutpb=P_MUTATION, ngen=MAX_GENERATIONS,stats=stats, verbose=True)    # gather statistics    maxFitnessValues, meanFitnessValues = logbook.select("max", "avg")    # plot statistics:    plt.plot(maxFitnessValues, color='red',label="Max Fitness")    plt.plot(meanFitnessValues, color='green',label="Average Fitness")    plt.legend()    plt.xlabel('Generation')    plt.ylabel('Fitness')    plt.title('Max and Average Fitness over Generations')    plt.show()    print(max(population,key=lambda ind:sum(ind)))if __name__ == "__main__":    main()

在上述代码中,我们定义了main()方程,运行该方程就可以进行遗传算法的运算,同时生成对应的统计数据与图表。

该方程中有以下步骤:

  1. 创建种群:种群大小为POPULATION_SIZE
  2. 初始化stats: 把个体的适应度收集进tools.Statistics对象。
  3. 通过algorithms.eaSimple方程运行遗传算法,并将最终的种群与统计数据分别存入population和logbbok变量:
  • population:初始的种群
  • toolbox:toolbox变量,该变量内包括了我们之前定义的evaluate, select, mate 和 mutate方程
  • cxpb:杂交概率
  • mutpb:突变概率
  • ngen:最大迭代代数
  • stats:Statistics对象,用以储存迭代过程中每一代种群的数据
  • verbose:在迭代过程中是否将Statistics输出至标准输出
  1. 从logbook变量中获取每一代适应度的最大值和均值
  1. 使用收集的数据画图,并显示适应度最高的个体,即最优解。
2b03085dfa887768176730497a50ba43.png

4. 运算结果

由下图所示,在第38代算法已经产生了最优解,即个体所有位置上都为1:[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]

当我们设置verbose=True时,algorithms.eaSimple会在迭代过程中实时生成每一代的数据并输出至标准输出:

gen     nevals  max     avg  0       200     65      50.351       191     62      52.9052       175     65      55.2253       189     67      57.3454       169     68      59.25 5       176     72      61.2856       170     73      63.3457       182     73      65.1658       179     74      66.8359       181     78      68.47510      188     80      70.13 11      178     82      71.95 12      189     81      73.75513      188     82      75.14514      194     83      76.75515      176     83      78.29 16      182     83      79.35 17      169     85      80.34 18      177     86      81.37 19      178     86      82.43520      184     87      83.31 21      179     88      84.17522      179     89      84.83523      179     90      85.57524      188     91      86.52525      189     93      87.55 26      181     94      88.44 27      190     94      89.31 28      185     95      89.94 29      174     96      90.7  30      188     98      91.41 31      180     98      92.19532      177     98      93.00533      179     98      93.83 34      175     98      94.55535      185     99      95.16536      179     99      95.72537      188     99      96.34538      182     100     97.0439      184     100     97.6340      183     100     98.0341      177     100     98.3742      192     100     98.68543      186     100     98.98544      175     100     99.32545      187     100     99.56546      171     100     99.7347      180     100     99.8948      186     100     99.8749      189     100     99.9150      187     100     99.9

5. 小结

本文中介绍了如何使用DEAP框架来解决OneMax问题,本系列的接下来几篇文中,我将详细解释algorithms.eaSimple如何运作,以及如何自定义tools.Statistics和logbook。

6. 完整代码

# 1.load modulesfrom deap import base,creator,tools,algorithmsimport randomimport numpy as npimport matplotlib.pyplot as plttoolbox = base.Toolbox()# 2.parameters:INDIVIDUAL_LENGTH = 100  # length of bit string to be optimizedPOPULATION_SIZE = 200P_CROSSOVER = 0.9  # probability for crossoverP_MUTATION = 0.1   # probability for mutating an individualMAX_GENERATIONS = 50random.seed(39)# 3.create individual and populationtoolbox.register("genBinary", random.randint, 0, 1)creator.create("FitnessMax", base.Fitness, weights=(1.0,))creator.create("Individual", list, fitness=creator.FitnessMax)toolbox.register("createIndividual", tools.initRepeat, creator.Individual, toolbox.genBinary, INDIVIDUAL_LENGTH)toolbox.register("createPopulation", tools.initRepeat, list, toolbox.createIndividual)# 4. define evaluation functiontoolbox.register("evaluate", lambda ind: (sum(ind),))# 5. define operatorstoolbox.register("select", tools.selTournament, tournsize=2)toolbox.register("mate", tools.cxOnePoint)toolbox.register("mutate", tools.mutFlipBit, indpb=1.0/INDIVIDUAL_LENGTH)# Genetic Algorithm flow:def main():    # create population    population = toolbox.createPopulation(n=POPULATION_SIZE)    # initialize statistics    stats = tools.Statistics(lambda ind: ind.fitness.values)    stats.register("max", np.max)    stats.register("avg", np.mean)    # Genetic Algorithm    population, logbook = algorithms.eaSimple(population, toolbox, cxpb=P_CROSSOVER,     mutpb=P_MUTATION, ngen=MAX_GENERATIONS,stats=stats, verbose=True)    # gather statistics    maxFitnessValues, meanFitnessValues = logbook.select("max", "avg")    # plot statistics:    plt.plot(maxFitnessValues, color='red',label="Max Fitness")    plt.plot(meanFitnessValues, color='green',label="Average Fitness")    plt.legend()    plt.xlabel('Generation')    plt.ylabel('Fitness')    plt.title('Max and Average Fitness over Generations')    plt.show()if __name__ == "__main__":    main()
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值