遗传算法的Python实现(通过遗传算法实现函数拟合)

遗传算法

简介

  遗传算法是允许高度并行的算法,工程师通常使用Cuda实现遗传算法以应用到工程实际中,笔者在这里以Python语法实现,旨在能让更多的人理解遗传算法。

问题描述

  利用遗传算法求解如下最优化问题
  min  F=i=13Wig(Qi)min \ \ F = \sum_{i=1}^{3}W_{i}g(Q_{i})
  其中 g(x)=0.1544×x2+1.181×x+0.6028g(x)=-0.1544\times x^{2}+1.181\times x+0.6028
  限制条件
  Qe=i=13WiQiQ_{e}=\sum_{i=1}^{3}W_{i}Q_{i}
  1.5Qi3.341.5\leq Q_{i} \leq 3.34
  Wi=01W_{i} = 0或1
  实现遗传算法主要有这样几步,第一步,编码

编码

  为了满足精度的同时避免使用小数点,我们需要将自变量QiQ_{i}乘以1000010000;当然也可以采用其它设计方法,这里考虑到编程工具和计算机算力,设为此值。
  Qi:(3.341.5)×10000=18400Q_{i}:(3.34-1.5)\times 10000 = 18400
  214184002152^{14}\leq 18400 \leq 2^{15}
  故对QiQ_{i}采用编码长度为15,对WiW_{i}采用编码长度为1

算法流程

  1.种群初始化
  2.选择
  3.繁殖
  4.变异
  5.是否满足循环次数:如果满足,则退出,否则,回到2

种群初始化

  首先需要对种群进行初始化

    #种群初始化
    def groupinit(self):
        for i in range(self.group_size):
            self.group.append(individual())
        for i in range(self.group_size):
            #总基因长度:15*2+1*2,即基因的前30位代码Q1,Q2...
            for j in range(32):
                self.group[i].gene[j] = random.randint(0,1)
        self.showgene()

将基因翻译成系数

    #基因展示(将具有相应基因的个体,将基因性质表达出来)
    def showgene(self):
        for i in range(self.group_size):
            temp = 0
            for j in range(15):
                temp|=self.group[i].gene[j]*2**j
            self.group[i].Q[0] = 1.5+ temp*(3.34-1.5)/(pow(2.0,15)-1)
            temp = 0
            for j in range(15):
                temp|=self.group[i].gene[j+15]*2**j
            self.group[i].Q[1] = 1.5+ temp*(3.34-1.5)/(pow(2.0,15)-1)
            #print(self.group[i].Q[0],self.group[i].Q[1])
            self.group[i].W[0]=self.group[i].gene[30]
            self.group[i].W[1]=self.group[i].gene[31]
            _ = self.Qe -self.group[i].W[0]*self.group[i].Q[0]-self.group[i].W[1]*self.group[i].Q[1]
            if _<1.5:
                self.group[i].flag = False
                self.group[i].fitness=0.0
            elif _ >3.34:
                self.group[i].flag = False
                self.group[i].W[2] = 0
                self.group[i].Q[2] = 0
                self.group[i].fitness=0.0
            else:
                self.group[i].flag = True
                self.group[i].W[2] = 1
                self.group[i].Q[2] = _
                _output = 0.0
                for k in range(3):
                   _output+=self.group[i].W[k]*((-0.1544)*self.group[i].Q[k]*self.group[i].Q[k]+1.181*self.group[i].Q[k]+0.6028)
                self.group[i].fitness =np.exp( -_output)

选择

  传统遗传算法的选择方式采用轮盘赌的方式将表现差的对象进行淘汰;但这里要解决问题的方式与传统的遗传算法解决的问题不一致。如果采用轮盘赌的方式,一些明明很接近有效值却因为不满足限制条件的个体则会被淘汰。这里仿照人类社会的方式进行选择。表现分最好的为国王,国王拥有绝对的存活率,表现分占前百分之十(不包括国王)的存活率是百分之九十,其它个体成为平民,平民拥有百分之七十的存活率。

 #自然选择
    def choose(self):

        #排序,找到国王与贵族(设置第一位国王,贵族,贫民,国王不会被选择淘汰,贵族百分之90的生存率,贫民百分之60)
        _noble = int(self.group_size/10)
        #存在限制条件,更类似于人类社会
        cmpfun = operator.attrgetter('fitness')#参数为排序依据的属性,可以有多个,这里优先id,使用时按需求改换参数即可
        self.group.sort(key =cmpfun,reverse = True)

        #for i in range(self.group_size):
        #    print(self.group[i].fitness)

        new_group = []
        new_group.append(self.group[0])
       
        #贵族
        for i in range(1,_noble):
            _rand = random.random()
            if(0.9>_rand):
                new_group.append(self.group[i])
        #平民
        for i in range(_noble,self.group_size):
            _rand = random.random()
            if(0.6>_rand):
                new_group.append(self.group[i])
        self.group = new_group

繁衍(基因交换)

  我们设置了种群规模,在选择之后,部分个体被淘汰,这里通过繁衍的方式让种群规模恢复。先随机选择父本和木本,然后选取交换基因的结点

    #繁衍(通过基因转换,构造新的种群)
    def Propagate(self):
        #繁衍第一步,随机选择父本和母本
        _len_group = len(self.group)
        _num = self.group_size - _len_group 
        for _i in range(_num):
            #随机选择父本和母本
            _father  = random.randint(0,_len_group-1)
            _mother = random.randint(0,_len_group-1)
            _gp = random.randint(0,31)#选择基因交换位置
            _ = individual()
            _.gene = self.group[_father].gene[0:_gp]+self.group[_mother].gene[_gp:32]
            self.group.append(_)

变异

  变异是遗传算法最为核心的内容,通过变异,引入了更多的基因型。

    #进行变异
    def mutation(self):
        #国王不发生变异,其余个体按照变异率进行变异
        for _i in range(1,self.group_size):
            _rand = random.random()
            if(self.mutationprop>_rand):
                _gp = random.randint(0,31)#选择基因变异的位置
                if(self.group[_i].gene[_gp]==1):
                    self.group[_i].gene[_gp] = 0
                else:
                    self.group[_i].gene[_gp] = 1

对原问题的思考

在这里插入图片描述

'''
file: plugin.py
本文根据作者的想法构建了一个特殊的遗传类
除模拟遗传算法外,还模拟了简单的人类社会
'''
import numpy as np
import random
import operator

def g(x):
    return np.float(-0.1544*x*x+1.181*x+0.6028)



class individual:
    def __init__(self):
        self.W = np.array([0.0,0.0,0.0],np.float)
        self.Q = np.array([0.0,0.0,0.0],np.float)
        self.gene =[0]*32
        self.falg = False
        self.fitness =0.0
        

class GA:
    '''
    para:
    group_size 种群数量
    Qe 限制条件中Qe的值
    '''
    def __init__(self,group_size,Qe,mutationprop):
        self.group_size = group_size
        self.group =[]
        self.Qe = Qe
        self.mutationprop = mutationprop
        self.groupinit()
        
    #种群初始化
    def groupinit(self):
        for i in range(self.group_size):
            self.group.append(individual())
        for i in range(self.group_size):
            #总基因长度:15*2+1*2,即基因的前30位代码Q1,Q2...
            for j in range(32):
                self.group[i].gene[j] = random.randint(0,1)
        self.showgene()
    #基因展示(将具有相应基因的个体,将基因性质表达出来)
    def showgene(self):
        for i in range(self.group_size):
            temp = 0
            for j in range(15):
                temp|=self.group[i].gene[j]*2**j
            self.group[i].Q[0] = 1.5+ temp*(3.34-1.5)/(pow(2.0,15)-1)
            temp = 0
            for j in range(15):
                temp|=self.group[i].gene[j+15]*2**j
            self.group[i].Q[1] = 1.5+ temp*(3.34-1.5)/(pow(2.0,15)-1)
            #print(self.group[i].Q[0],self.group[i].Q[1])
            self.group[i].W[0]=self.group[i].gene[30]
            self.group[i].W[1]=self.group[i].gene[31]
            _ = self.Qe -self.group[i].W[0]*self.group[i].Q[0]-self.group[i].W[1]*self.group[i].Q[1]
            if _<1.5:
                self.group[i].flag = False
                self.group[i].fitness=0.0
            elif _ >3.34:
                self.group[i].flag = False
                self.group[i].W[2] = 0
                self.group[i].Q[2] = 0
                self.group[i].fitness=0.0
            else:
                self.group[i].flag = True
                self.group[i].W[2] = 1
                self.group[i].Q[2] = _
                _output = 0.0
                for k in range(3):
                   _output+=self.group[i].W[k]*((-0.1544)*self.group[i].Q[k]*self.group[i].Q[k]+1.181*self.group[i].Q[k]+0.6028)
                self.group[i].fitness =np.exp( -_output)



    #自然选择
    def choose(self):

        #排序,找到国王与贵族(设置第一位国王,贵族,贫民,国王不会被选择淘汰,贵族百分之90的生存率,贫民百分之60)
        _noble = int(self.group_size/10)
        #存在限制条件,更类似于人类社会
        cmpfun = operator.attrgetter('fitness')#参数为排序依据的属性,可以有多个,这里优先id,使用时按需求改换参数即可
        self.group.sort(key =cmpfun,reverse = True)

        #for i in range(self.group_size):
        #    print(self.group[i].fitness)

        new_group = []
        new_group.append(self.group[0])
       
        #贵族
        for i in range(1,_noble):
            _rand = random.random()
            if(0.9>_rand):
                new_group.append(self.group[i])
        #平民
        for i in range(_noble,self.group_size):
            _rand = random.random()
            if(0.6>_rand):
                new_group.append(self.group[i])
        self.group = new_group
    #繁衍(通过基因转换,构造新的种群)
    def Propagate(self):
        #繁衍第一步,随机选择父本和母本
        _len_group = len(self.group)
        _num = self.group_size - _len_group 
        for _i in range(_num):
            #随机选择父本和母本
            _father  = random.randint(0,_len_group-1)
            _mother = random.randint(0,_len_group-1)
            _gp = random.randint(0,31)#选择基因交换位置
            _ = individual()
            _.gene = self.group[_father].gene[0:_gp]+self.group[_mother].gene[_gp:32]
            self.group.append(_)
    
    #进行变异
    def mutation(self):
        #国王不发生变异,其余个体按照变异率进行变异
        for _i in range(1,self.group_size):
            _rand = random.random()
            if(self.mutationprop>_rand):
                _gp = random.randint(0,31)#选择基因变异的位置
                if(self.group[_i].gene[_gp]==1):
                    self.group[_i].gene[_gp] = 0
                else:
                    self.group[_i].gene[_gp] = 1

        #打印国王信息
    def showtheking(self):
        print("国王的信息")
        print("适应度",self.group[0].fitness)
        print("系数W",self.group[0].W[0],self.group[0].W[1],self.group[0].W[2])
        print("系数Q",self.group[0].Q[0],self.group[0].Q[1],self.group[0].Q[2])
        print("函数的最优解",-np.log(self.group[0].fitness))
    def showgroup(self):
        for i in range(self.group_size):
            print("适应度",self.group[i].fitness)
            print("系数W",self.group[i].W[0],self.group[i].W[1],self.group[i].W[2])
            print("系数Q",self.group[i].Q[0],self.group[i].Q[1],self.group[i].Q[2])
            print("函数的值",-np.log(self.group[i].fitness))
    def run(self,_cyclenum):
        for _i in range(_cyclenum):
            self.choose()
            self.Propagate()
            self.mutation()
            self.showgene()
            #self.showtheking()
        self.showgroup()
        self.showtheking()
#file main.py

from plugin import GA


if __name__ == "__main__":

    _ga =GA(4000,3.62,0.2)
    _ga.run(400)

Python推广

  使用Python或者OCtave,matlab等编程语言进行开发是十分有必要的,先用便捷的编程语言验证算法的可行性,再用C++/Java去实现算法,这一点对算法工程师来说,尤为重要。读者可以加入QQ群,交流学习Python
916372346。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章