遗传算法

Posted yof3ng

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了遗传算法相关的知识,希望对你有一定的参考价值。

目录


title: 遗传算法
date: 2018-10-17 19:26:39
tags: [数学建模,算法,algorithm]
categories: 算法
img: https://i.loli.net/2018/10/17/5bc71d6db996b.png
---

欢迎前往个人主页,进行更优质的阅览,https://yof3ng.github.io

遗传算法(Genetic Algorithm)

算法都是用来解决实际问题,提高效率的,而学好算法对一个信息安全从业者来说,应该也是必要的。开始接触这些算法,也逐渐意识到知识面广阔的重要,比如遗传算法就需要知道一定的生物知识,可能这就是培训机构无法弥补的地方吧。

简介

先引用一下遗传算法的解释:

? ? ? ? 遗传算法(Genetic Algorithm)是模拟达尔文生物进化论的自然选择和遗传学机理的生物进化过程的计算模型,是一种通过模拟自然进化过程搜索最优解的方法。遗传算法是从代表问题可能潜在的解集的一个种群(population)开始的,而一个种群则由经过基因(gene)编码的一定数目的个体(individual)组成。

? ? ? ? 每个个体实际上是染色体(chromosome)带有特征的实体。染色体作为遗传物质的主要载体,即多个基因的集合,其内部表现(即基因型)是某种基因组合,它决定了个体的形状的外部表现,如黑头发的特征是由染色体中控制这一特征的某种基因组合决定的。因此,在一开始需要实现从表现型到基因型的映射即编码工作。由于仿照基因编码的工作很复杂,我们往往进行简化,如二进制编码,初代种群产生之后,按照适者生存和优胜劣汰的原理,逐代(generation)演化产生出越来越好的近似解,在每一代,根据问题域中个体的适应度(fitness)大小选择(selection)个体,并借助于自然遗传学的遗传算子(genetic operators)进行组合交叉(crossover)和变异(mutation),产生出代表新的解集的种群。这个过程将导致种群像自然进化一样的后生代种群比前代更加适应于环境,末代种群中的最优个体经过解码(decoding),可以作为问题近似最优解。

遗传算法的组成主要包括4个部分:
(1)编码
(2)适应度函数
(3)遗传算子(选择,交叉,变异)
(4)运行参数

选择、交叉和变异构成了遗传算法的遗传操作;参数编码、初始群体的设定、适应度函数的设计、遗传操作设计、控制参数设定五个要素组成了遗传算法的核心内容。

技术分享图片

编码与解码

? ? ? ? 遗传算法的实行,首先需要确定编码和解码的形式,生物体的遗传就是通过染色体以及基因进行,编码形式多种多样,能够使用字母,实数,或者是二进制来进行编码。但是因为博主刚开始学遗传算法,便拿SGA(基本遗传算法)来对遗传算法进行一个简单的理解。

直接上例题说明:

技术分享图片

我们需要求此函数在[-2,2]区间下的最大值,先用python画一下函数图形。

#coding:utf-8
__Author__ = "Yof3ng"

import math
import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(-2,2,10000)
y=[]
#通过循环计算每一个x值对应的y值
for i in x:
  a= 200*np.exp(-0.05*i)*(math.sin(i))
  y.append(a)
#通过matplotlib库绘出函数图形
plt.plot(x,y)
plt.annotate('local max', xy=(1.4, max(y)), xytext=(0, 200),
            arrowprops=dict(facecolor='black', shrink=0.05),
            )
plt.show()

函数图像如下:

技术分享图片

[-2,2]区间已经分为10000个等份,而我们需要找出最大值,SGA基本遗传算法就是用二进制编码来表示的,那么我们把2^14,即十四位二进制用作编码来表示个体:

技术分享图片

初始化种群

已经决定用十四位二进制来表示种群个体了,那么我们就可以对种群进行初始化:

#初始化种群个体
def Init_popu(number):
  population=[]
  for i  in range(number):
      entity=''
       #随机产生个体
      for j in range(14):
          entity = entity+str(np.random.randint(0,2))
      population.append(entity)
  return population

将种群初始化编码后,自定义解码方法:

#解码
def Decode(population):
  flag = 0
  Dpopulation = []
  #print(population)
  for i in population:
      #将二进制转换为整型数值
      x = eval('0b'+i)
      x = x/(2**14-1)*4-2
      Dpopulation.append(x)
      # someone = str(population[flag])
      # express[i] = DNAdict[someone]
  return population,Dpopulation
  #return express
  # print(bx[0:100])
  # print(ast.literal_eval('0b'+bx[1]))

计算适应度

根据种群个体的适应度我们可以进行后面的选择淘汰方法,不同的问题有不同的适应度计算方法
而本例题则,直接用目标函数作为适应度函数

#根据函数原型计算表现型(y值),即适应度
def gafunction(population,dpopulation):
  y=[]
  flag=0
  pp=[]
  #通过循环计算每一个x值对应的y值
  for i in dpopulation:
      a= 200*np.exp(-0.05*i)*(math.sin(i))
      y.append(a)
  #由于是计算最大值,若存在正数则直接去除负数个体
  for i in y:
      if i>0:
          flag=1
  yy =[]
  n=0
  if flag==1:
      for i in y:
          if i>0:
              yy.append(i)
              pp.append(population[n])
          n+=1
      return yy,pp
  else:
      return y,population

定义选择方法

个体生存概率公式:

技术分享图片

技术分享图片

根据适应度以及遗传概率,进行选择:

#定义物竞天择,弱者淘汰
def selection(population,y):
  #轮盘赌选择,染色体累计概率
  fitness_sum=[]
  for i in range(len(y)):
      if i==0:
          fitness_sum.append(y[i])
      else:
          fitness_sum.append(fitness_sum[i-1]+y[i])
  for i in range(len(fitness_sum)):
      fitness_sum[i]/=sum(y)
  #进行选择,淘汰弱者,获取新种群
  population_new=[]
  for i in range(len(y)):
      rand=np.random.uniform(0,1)
      for j in range(len(y)):
          if j==0:
              if 0<rand and rand<=fitness_sum[j]:
                  population_new.append(population[j])
          else:
              if fitness_sum[j-1]<rand and rand<=fitness_sum[j]:
                  population_new.append(population[j])
  flag = 0
  
  new_population=[]
  #留下优秀个体
  for i in set(population_new):
      new_population.append(i)
  return new_population
  #return population_new

定义交叉方法

像染色体一样,也进行交叉操作,并且给与交叉操作产生的概率:

#交叉算子
def crossover(population_new, pc):
  half=int(len(population_new)/2)
  father=population_new[:half]
  mother=population_new[half:]
  np.random.shuffle(father)
  np.random.shuffle(mother)
  offspring=[]
  for i in range(half):      
      if np.random.uniform(0,1)<=pc:
          copint = np.random.randint(0,int(len(father[i])/2))
          son=father[i][:copint]+(mother[i][copint:])
          daughter=mother[i][:copint]+(father[i][copint:])
      else:
          son=father[i]
          daughter=mother[i]
      offspring.append(son)
      offspring.append(daughter)
  return offspring

定义变异方法

即使基因突变的概率极小,但也需要定义一个基因突变方法:

#变异算子
def mutation(offspring,pm):
  for i in range(len(offspring)):
      if np.random.uniform(0,1)<=pm:
          position=np.random.randint(0,len(offspring[i]))
          #'str' object does not support item assignment,cannot use = to change value
          if position!=0:
              if offspring[i][position]=='1':
                  offspring[i]=offspring[i][:position-1]+'0'+offspring[i][position:]
              else:
                  offspring[i]=offspring[i][:position-1]+'1'+offspring[i][position:]
          else:
              if offspring[i][position]=='1':
                  offspring[i]='0'+offspring[i][1:]
              else:
                  offspring[i]='1'+offspring[i][1:]
  return offspring

开始迭代进化

主函数如下:

if __name__=="__main__":
  #通过matplotlib库绘出函数图形
  # plt.plot(x,y)
  # plt.annotate('local max', xy=(1.4, max(y)), xytext=(0, 200),
  #             arrowprops=dict(facecolor='black', shrink=0.05),
  #             )
  # plt.show()
  population = Init_popu(2000)
  mean = []
  X=[]
  Y=[]
  Y1=[]
  Y2=[]
  for i in range(10):
      population,Dpopulation = Decode(population)
      y,population = gafunction(population,Dpopulation)
      #print(DNAdict)
      new_population = selection(population,y)
      #crossover 交叉
      offspring =crossover(new_population,0.8)
      #mutation 变异
      population=mutation(offspring,0.001)
      population,Dpopulation = Decode(population)
      y,population = gafunction(population,Dpopulation)
      #通过平均值表示迭代进化
      meannum = np.mean(y)
      #通过最小值表示迭代进化
      minnum = min(y)
      #通过最大值表示迭代进化
      maxnum = max(y)
      X.append(i)
      Y.append(minnum)
      Y1.append(meannum)
      Y2.append(maxnum)
  
  plt.plot(X,Y,color='b')
  plt.plot(X,Y2,color='g')
  plt.plot(X,Y1,color='y')
  plt.axhline(FuncMax(), linewidth=1, color='r')  
  plt.show()    
      



遗传算法实例运行效果如下:

技术分享图片

现在对遗传算法也大概有个简单的了解啦,暂时到这儿。

附上完整代码:https://github.com/Yof3ng/algorithm/blob/master/SGA.py

#coding:utf-8
__Author__ = "Yof3ng"

import math
import numpy as np
import matplotlib.pyplot as plt

def FuncMax():
    xx = np.linspace(-2,2,1000)
    yy=[]
    #通过循环计算每一个x值对应的y值
    for ii in xx:
        a= 200*np.exp(-0.05*ii)*(math.sin(ii))
        yy.append(a)
    return max(yy)

#根据函数原型计算表现型(y值),即适应度
def gafunction(population,dpopulation):
    y=[]
    flag=0
    pp=[]
    #通过循环计算每一个x值对应的y值
    for i in dpopulation:
        a= 200*np.exp(-0.05*i)*(math.sin(i))
        y.append(a)
    #由于是计算最大值,若存在正数则直接去除负数个体
    for i in y:
        if i>0:
            flag=1
    yy =[]
    n=0
    if flag==1:
        for i in y:
            if i>0:
                yy.append(i)
                pp.append(population[n])
            n+=1
        return yy,pp
    else:
        return y,population


#解码
def Decode(population):
    flag = 0
    Dpopulation = []
    #print(population)
    for i in population:
        #将二进制转换为整型数值
        x = eval('0b'+i)
        x = x/(2**14-1)*4-2
        Dpopulation.append(x)
        # someone = str(population[flag])
        # express[i] = DNAdict[someone]
    return population,Dpopulation
    #return express
    # print(bx[0:100])
    # print(ast.literal_eval('0b'+bx[1]))

#初始化个体
def Init_popu(number):
    population=[]
    for i  in range(number):
        entity=''
        for j in range(14):
            entity = entity+str(np.random.randint(0,2))
        population.append(entity)
    return population

#定义物竞天择,弱者淘汰
def selection(population,y):
    #轮盘赌选择,染色体累计概率
    fitness_sum=[]
    for i in range(len(y)):
        if i==0:
            fitness_sum.append(y[i])
        else:
            fitness_sum.append(fitness_sum[i-1]+y[i])
    for i in range(len(fitness_sum)):
        fitness_sum[i]/=sum(y)
    #进行选择,淘汰弱者,获取新种群
    population_new=[]
    for i in range(len(y)):
        rand=np.random.uniform(0,1)
        for j in range(len(y)):
            if j==0:
                if 0<rand and rand<=fitness_sum[j]:
                    population_new.append(population[j])
            else:
                if fitness_sum[j-1]<rand and rand<=fitness_sum[j]:
                    population_new.append(population[j])
    flag = 0
    
    new_population=[]
    #留下优秀个体
    for i in set(population_new):
        new_population.append(i)
    return new_population
    #return population_new

#交叉算子
def crossover(population_new, pc):
    half=int(len(population_new)/2)
    father=population_new[:half]
    mother=population_new[half:]
    np.random.shuffle(father)
    np.random.shuffle(mother)
    offspring=[]
    for i in range(half):      
        if np.random.uniform(0,1)<=pc:
            copint = np.random.randint(0,int(len(father[i])/2))
            son=father[i][:copint]+(mother[i][copint:])
            daughter=mother[i][:copint]+(father[i][copint:])
        else:
            son=father[i]
            daughter=mother[i]
        offspring.append(son)
        offspring.append(daughter)
    return offspring

#变异算子
def mutation(offspring,pm):
    for i in range(len(offspring)):
        if np.random.uniform(0,1)<=pm:
            position=np.random.randint(0,len(offspring[i]))
            #'str' object does not support item assignment,cannot use = to change value
            if position!=0:
                if offspring[i][position]=='1':
                    offspring[i]=offspring[i][:position-1]+'0'+offspring[i][position:]
                else:
                    offspring[i]=offspring[i][:position-1]+'1'+offspring[i][position:]
            else:
                if offspring[i][position]=='1':
                    offspring[i]='0'+offspring[i][1:]
                else:
                    offspring[i]='1'+offspring[i][1:]
    return offspring

if __name__=="__main__":
    #通过matplotlib库绘出函数图形
    # plt.plot(x,y)
    # plt.annotate('local max', xy=(1.4, max(y)), xytext=(0, 200),
    #             arrowprops=dict(facecolor='black', shrink=0.05),
    #             )
    # plt.show()
    population = Init_popu(2000)
    mean = []
    X=[]
    Y=[]
    Y1=[]
    Y2=[]
    for i in range(10):
        population,Dpopulation = Decode(population)
        y,population = gafunction(population,Dpopulation)
        #print(DNAdict)
        new_population = selection(population,y)
        #crossover 交叉
        offspring =crossover(new_population,0.8)
        #mutation 变异
        population=mutation(offspring,0.001)
        population,Dpopulation = Decode(population)
        y,population = gafunction(population,Dpopulation)
        #通过平均值表示迭代进化
        meannum = np.mean(y)
        #通过最小值表示迭代进化
        minnum = min(y)
        #通过最大值表示迭代进化
        maxnum = max(y)
        X.append(i)
        Y.append(minnum)
        Y1.append(meannum)
        Y2.append(maxnum)
    
    plt.plot(X,Y,color='b')
    plt.plot(X,Y2,color='g')
    plt.plot(X,Y1,color='y')
    plt.axhline(FuncMax(), linewidth=1, color='r')  
    plt.show()    
        


参考:

https://www.cnblogs.com/ECJTUACM-873284962/p/8857950.html

https://blog.csdn.net/WFRainn/article/details/80458246

以上是关于遗传算法的主要内容,如果未能解决你的问题,请参考以下文章

遗传算法介绍并附上Python代码

运行遗基于遗传算法的BP神经网络MATLAB代码程序时总是出错!!!???

基于遗传算法实现TSP问题求解matlab代码

c语言实现*/遗传算法改进BP神经网络原理和算法实现怎么弄

使用Python实现的遗传算法 附完整代码

MATLAB实战系列(二十六)-遗传算法求解车间调度问题