遗传算法(Genetic Algorithm)顾名思义,是一种基于自然选择原理和自然遗传机制的启发式搜索算法。该算法通过模拟自然界中生物遗传进化的自然机制(选择、交叉和变异操作),将好的遗传基因(最优目标)不断遗传给子代,使得后代产生最优解的概率增加(后代还是会有一些差的结果)。它的整个算法流程如下:
- 首先根据具体问题确定可行解域和编码方式,用数值串或字符串的形式表示可行解域中的每一个可行解;
- 构建适应度函数度量每一解,该函数为非负函数;
- 确定种群的大小、选择、交叉和变异的方式、交叉和变异的概率,判断终止条件(可以是某一阈值或者是指定进化的代数)。
在这个过程当中,交叉操作是优化的主要操作,而变异操作可以看成对种群的扰动。根据具体的问题我们构建适应度函数,并优化极值(可以是求最大值,也可以求最小值)。
名词解析
生物遗传概念在遗传算法中的对应关系如下:
生物遗传概念 | 遗传算法中的作用 |
---|---|
适者生存 | 算法停止时,最优目标值的解大概率被找到 |
个体 | 每个可行解 |
染色体 | 对每个可行解的编码 |
基因 | 可行解中的每个组成部分 |
适应性 | 适应度函数的函数值 |
种群 | 可行解域,根据适应度函数选择的一组解 |
选择 | 保留适应度函数的函数值优的解 |
交叉 | 将两个可行解内的组分随机交叉,产生新解 |
变异 | 随机变异可行解中的某些组分 |
算法步骤
我们还是以一个简单的例子来讲解整个算法的流程。比如,我们需要寻找函数y=x12+x22+x33+x44
在[1,30]
之间的最大值。我们很容易就知道,当x1=x2=x3=x4=30
时,该函数能取到最大值。
首先我们构建一个叫Gene
的类:
1 2 3 4 |
class Gene: def __init__(self, **data): self.__dict__.update(data) self.size = len(data['data']) # length of gene |
这个类只有一个初始化方法,该方法就是获得基因里面的内容和大小,在这个例子中,内容就是[1,30]
之间的任意4个数字组成的列表。
接着构建一个叫GA
的类,这个类包括算法的所有操作方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
class GA: def __init__(self, parameter): pass def evaluate(self, geneinfo): pass def selectBest(self, pop): pass def selection(self, individuals, k): pass def crossoperate(self, offspring): pass def mutation(self, crossoff, bound): pass def GA_main(self): pass |
使用__init__()
方法初始化参数,包括自变量可取的最大值,最小值,种群大小,交叉率,变异率和繁殖代数;使用evaluate()
方法作为适应度函数评估该个体的函数值,在这里就是函数y
的值;使用selectBest()
方法挑选出当前代种群中的最好个体作为历史记录;使用selection()
方法按照概率从上一代种群中选择个体,直至形成新的一代;使用crossoperate()
方法实现交叉操作;使用mutation()
方法实现变异操作;使用GA_main()
方法实现整个算法的循环。
接下来我们会一一对其进行解析。
__init__()方法
__init__()
方法的代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
def __init__(self, parameter): # parameter = [CXPB, MUTPB, NGEN, popsize, low, up] self.parameter = parameter low = self.parameter[4] up = self.parameter[5] self.bound = [] self.bound.append(low) self.bound.append(up) pop = [] for i in range(self.parameter[3]): geneinfo = [] for pos in range(len(low)): geneinfo.append(random.randint(self.bound[0][pos], self.bound[1][pos])) # initialise popluation fitness = self.evaluate(geneinfo) # evaluate each chromosome pop.append({'Gene': Gene(data=geneinfo), 'fitness': fitness}) # store the chromosome and its fitness self.pop = pop self.bestindividual = self.selectBest(self.pop) # store the best chromosome in the population |
初始化方法接受传入的参数,包括最大值,最小值,种群大小,交叉率,变异率和繁殖代数。通过这些参数随机产生一个种群的列表pop
作为首代种群,里面的每一条染色体是一个字典,该字典有两个内容,分别是包含基因的Gene
类和适应度函数值fitness
。
evaluate()方法
在初始化方法中,要用到适应度函数计算函数值,它的定义如下:
1 2 3 4 5 6 7 |
def evaluate(self, geneinfo): x1 = geneinfo[0] x2 = geneinfo[1] x3 = geneinfo[2] x4 = geneinfo[3] y = x1**2 + x2**2 + x3**3 + x4**4 return y |
selectBest()方法
在初始化方法中,需要先将首代中最好的个体保留作为记录&