遗传算法之Python实现

作者: 老梁家的风子 | 来源:发表于2017-10-10 00:24 被阅读501次

    遗传算法之Python实现

    写在前面

    之前的文章中已经讲过了遗传算法的基本流程,并且用MATLAB实现过一遍了。这一篇文章主要面对的人群是看过了我之前的文章,因此我就不再赘述遗传算法是什么以及基本的内容了,假设大家已经知道我是怎么写遗传算法的了。

    Python的遗传算法主函数

    我的思想是,创建一个染色体的类,其中包括了两个变量:染色体chrom与适应度fitness。因此我们就可以通过直接建立对象来作为种群中的个体。

    #染色体的类
    class Chrom:
        chrom = []
        fitness = 0
        def showChrom(self):
            print(self.chrom)
        def showFitness(self):
            print(self.fitness)
    

    所以我们开始设置基础参数。其中种群的表达方式我用的是字典,也就是用一个字典来保存种群内的所有个体,这个也是我想出来的创建多个对象的方法。

    将字典的索引为个体的标号,如:chrom1, chrom2等。字典索引的值就是一个对象。这个对象拥有两个属性,就是染色体与适应度。

    其实在这一方便来说,我觉得在思路上是优于利用MATLAB的矩阵式编程的。因为这样可以很直观的将个体与个体的属性这一种思想给表达出来,相比一堆矩阵来说,在逻辑上比较容易接受。

    #基础参数
    N = 200  #种群内个体数目
    mut = 0.2  #突变概率
    acr = 0.2  #交叉概率
    
    pop = {}  #存储染色体的字典
    for i in range(N):
        pop['chrom'+str(i)] = Chrom()
    chromNodes = 2  #染色体节点数(变量个数)
    iterNum = 10000  #迭代次数
    chromRange = [[0, 10], [0, 10]]  #染色体范围
    aveFitnessList = []  #平均适应度
    bestFitnessList = []  #最优适应度
    

    之后就是初始染色体了,其中就牵扯到了各种用来初始化种群、计算适应度、找最优等函数,我在这里分出了两个文件,分别为Genetic.py与Fitness.py。

    Genetic.py里面有八个函数,主要包含了作用于种群或者染色体操作的函数,分别为:

    • findBest函数,用于寻找种群中的最优染色体;
    • findworse函数,用于寻找种群中的最劣染色体;
    • initialize函数,用于初始化种群;
    • calAveFitness函数,用于计算种群的平均适应度;
    • mutChrom函数,用于对染色体进行变异;
    • inRange函数,用于判断染色体节点值是否越界;
    • acrChrom函数,用于对染色体进行交叉;
    • compareChrom函数,用于比较两个染色体孰优孰劣。

    Fitness.py里面有两个函数,主要包含了对适应度操作的函数,分别为:

    • calFitness函数,用来迭代每一个个体,并计算适应度(利用funcFitness函数计算);
    • funcFitness函数,计算单个个体的适应度。

    因此可以列出初始化代码为

    #初始染色体
    pop = Genetic.initialize(pop, chromNodes, chromRange)
    pop = Fitness.calFitness(pop)  #计算适应度
    bestChrom = Genetic.findBest(pop)  #寻找最优染色体
    bestFitnessList.append(bestChrom[1])  #将当前最优适应度压入列表中
    aveFitnessList.append(Genetic.calAveFitness(pop, N))  #计算并存储平均适应度
    

    迭代过程的思路和逻辑与MATLAB无异

    #开始迭代
    for t in range(iterNum):
        #染色体突变
        pop = Genetic.mutChrom(pop, mut, chromNodes, bestChrom, chromRange)
        #染色体交换
        pop = Genetic.acrChrom(pop, acr, chromNodes)
        #寻找最优
        nowBestChrom = Genetic.findBest(pop)
        #比较前一个时间的最优和现在的最优
        bestChrom = Genetic.compareChrom(nowBestChrom, bestChrom)
        #寻找与替换最劣
        worseChrom = Genetic.findWorse(pop)
        pop[worseChrom[0]].chrom = pop[bestChrom[0]].chrom.copy()
        pop[worseChrom[0]].fitness = pop[bestChrom[0]].fitness
        #存储最优与平均
        bestFitnessList.append(bestChrom[1])
        aveFitnessList.append(Genetic.calAveFitness(pop, N))
    

    最后再做一下迭代的的图像

    plt.figure(1)
    plt.plot(x, aveFitnessList)
    plt.plot(x, bestFitnessList)
    plt.show()
    

    最后再在最前面加上各种库和文件就可以运行了。

    import Genetic
    import Fitness
    import matplotlib.pyplot as plt
    import numpy as np
    

    感悟

    可以说最主要的感悟就是染色体这一个类。其实那个Genetic.py与Fitness.py这两个文件也可以直接包装成类,但是这样一来我就嫌主文件太臃肿,在其他里面再包装成类又多此一举,毕竟这只是一个小程序,所以我就这样写了。

    深刻感悟到了面向对象编程的优点,在编程逻辑的处理上真是一种享受,只需要思考对象的属性即可,省去了许多复杂的思考。

    另一个感悟就是创建多个对象时,利用字典的方法来创建对象。当初我也是困惑怎么建立一个类似于C++中的对象数组,上网查找了各种方法,结果都避而不谈(当然,也可能是我搜索能力太差没找到),所以经过尝试中遇到到了这种方法。

    等有空我再详细说一下这个方法吧,这一次就先到这里。

    剩余的函数补充

    首先是Genetic.py里面的八个函数

    
    import random
    
    #寻找最优染色体
    def findBest(pop):
        best = ['1', 0.0000001]
        for i in pop:
            if best[1] < pop[i].fitness:
                best = [i, pop[i].fitness]
        return best
    
    #寻找最劣染色体
    def findWorse(pop):
        worse = ['1', 999999]
        for i in pop:
            if worse[1] > pop[i].fitness:
                worse = [i, pop[i].fitness]
        return worse
    
    #赋初始值
    def initialize(pop, chromNodes, chromRange):
        for i in pop:
            chromList = []
            for j in range(chromNodes):
                chromList.append(random.uniform(chromRange[j][0], chromRange[j][1]+1))
            pop[i].chrom = chromList.copy()
        return pop
    
    #计算平均适应度
    def calAveFitness(pop, N):
        sumFitness = 0
        for i in pop:
            sumFitness = sumFitness + pop[i].fitness
        aveFitness = sumFitness / N
        return aveFitness
    
    #进行突变
    def mutChrom(pop, mut, chromNodes, bestChrom, chromRange):
        for i in pop:
            #如果随机数小于变异概率(即可以变异)
            if mut > random.random():
                mutNode = random.randrange(0,chromNodes)
                mutRange = random.random() * (1-pop[i].fitness/bestChrom[1])**2
                pop[i].chrom[mutNode] = pop[i].chrom[mutNode] * (1+mutRange)
                #判断变异后的范围是否在要求范围内
                pop[i].chrom[mutNode] = inRange(pop[i].chrom[mutNode], chromRange[mutNode])
        return pop
    
    #检验便宜范围是否在要求范围内
    def inRange(mutNode, chromRange):
        if chromRange[0] < mutNode < chromRange[1]:
            return mutNode
        elif mutNode-chromRange[0] > mutNode-chromRange[1]:
            return chromRange[1]
        else:
            return chromRange[0]
    
    #进行交叉
    def acrChrom(pop, acr, chromNodes):
        for i in pop:
            for j in pop:
                if acr > random.random():
                    acrNode = random.randrange(0, chromNodes)
                    #两个染色体节点进行交换
                    pop[i].chrom[acrNode], pop[j].chrom[acrNode] = pop[j].chrom[acrNode], pop[i].chrom[acrNode]
        return pop
    
    #进行比较
    def compareChrom(nowbestChrom, bestChrom):
        if bestChrom[1] > nowbestChrom[1]:
            return bestChrom
        else:
            return nowbestChrom
    

    然后是Fitness.py的两个函数

    import math
    
    def calFitness(pop):
        
        for i in pop:
            #计算每个染色体的适应度
            pop[i].fitness = funcFitness(pop[i].chrom)
    
        return pop
    
    def funcFitness(chrom):
        #适应度函数
        fitness = math.sin(chrom[0])+math.cos(chrom[1])+0.1*(chrom[0]+chrom[1])
    
        return fitness
    

    以上。

    喜欢的话麻烦点个喜欢哦~

    相关文章

      网友评论

      • 雕刻君:你好,请问提示这个错误是怎么回事?
        File "<ipython-input-16-6c1a2206eb3f>", line 33, in <module>
        bestChrom = Genetic.findBest(pop) #寻找最优染色体

        File "D:\Anaconda\程序\遗传算法\Genetic.py", line 14, in findBest
        if best[1] < pop[i].fitness:

        TypeError: '<' not supported between instances of 'float' and 'NoneType'
        老梁家的风子:@雕刻君 没有赋值可能
      • 286e35f9a97c:plt.plot(x, aveFitnessList)
        plt.plot(x, bestFitnessList)
        请问这里的x是什么?
        老梁家的风子:@桃儿桃 谢谢夸奖
        286e35f9a97c:@老梁家的风子 客气啦,你的代码写得很清楚,一看就明白👍👍👍
        老梁家的风子:@桃儿桃 啊抱歉,我少放上去一句x的定义,应该还有一行
        x=list(range(iterNum+1))

      本文标题:遗传算法之Python实现

      本文链接:https://www.haomeiwen.com/subject/ctmmyxtx.html