Advertisement

优化算法-遗传算法

阅读量:

优化算法-遗传算法

主要参考了集体智慧编程一书

之前已经实现过优化算法中的爬山法和模拟退火法,现在我们讨论一下另一种受自然科学启发的算法:遗传算法。借鉴生物进化论,遗传算法将要解决的问题模拟成一个生物进化的过程,通过复制、交叉、突变等操作产生下一代的解,并逐步淘汰掉适应度函数值低的解,留下适应度函数值高的解。这样进化N代后就很有可能会进化出适应度函数值很高的个体。

一. 遗传算法流程

1.首先我们要初始化一组解(数量为事先设定的种群大小)。

2.现在我们要使目标函数最小,那么我们要逐步淘汰掉使目标函数值高的解,留下使目标函数值小的解,再将留下来的解通过复制、交叉、突变等操作产生下一代的解(比如我们留下使目标函数值最小的20%解,然后基于这最小的20%解复制、交叉、突变等操作产生下一代解),恢复种群原来的大小。

3.然后开始重复第二步操作,直到达到结束条件。

二. 遗传算法的基本操作

使用遗传算法需要先将问题的解进行编码。最简单的一种编码方式是二进制编码,即将问题的解编码成二进制位数组的形式。例如,问题的解是整数,那么可以将其编码成二进制位数组的形式,当然也可以直接使用这些整数作为编码(适用于解的维度比较大的情况)。

遗传算法有3个最基本的操作:选择,交叉,变异。

  • 1.选择: 我们将当前种群中最优的一部分解加入其所在的新种群中,而将当前种群中不属于最优的一部分解淘汰。选取最优一般是按比例选取,这个在前文已经有了介绍。

  • 2.交叉: 这种方法是在新种群中选取之前步骤加入的最优解中的两个解,然后将它们按照某种方式结合。实现交叉的简单方法是:选出两个最优解后,从一个最优解中随机选取一个数,将此数之前的值作为新解的前面元素的值,而剩余的元素来源于另一个选出的最优解。

交叉操作python实现:

复制代码
    # 交叉操作
    # vec1和vec2是选出两个最优解
    # dismension是一个解的维度len(range_list)
    def crossover(vec1, vec2, dimension):
    # 选出交叉位置
    i = random.randint(1, dimension-2)
    return vec1[0:i]+vec2[i:]
  • 3.变异:
    通常做法是对一个已有解进行微小的、简单的、随机的改变。

变异操作python实现:

复制代码
    # 变异操作
    # vec是要变异操作的已有解,step是变异的幅度
    # range_list是一个二维list构成的列表
    # range_list指定了一个解中的每个变量的最大最小值,相当于定义域
    def crossover(vec, range_list, step=1):
    dimension = len(range_list)
    i = random.randint(1, dimension - 1)
    if random.random()<0.5 and vec[i]>range_list[i][0]:
        return vec[0:i] + [vec[i]-step] + vec[i+1:]
    elif vec[i]<range_list[i][1]:
        return vec[0:i] + [vec[i]+step] + vec[i+1:]

三. 遗传算法的python实现

复制代码
    # 遗传算法
    # cost_func是代价函数,目标便是让代价函数最小
    # range_list是一个二维list构成的列表
    # range_list指定了一个解中的每个变量的最大最小值,相当于定义域
    
    # 交叉操作
    # vec1和vec2是选出两个最优解
    # dismension是一个解的维度len(range_list)
    def crossover(vec1, vec2, dimension):
    # 选出交叉位置
    i = random.randint(1, dimension-2)
    return vec1[0:i]+vec2[i:]
    
    # 变异操作
    # vec是要变异操作的已有解,step是变异的幅度
    def alter(vec, range_list, step=1):
    dimension = len(range_list)
    i = random.randint(1, dimension - 1)
    if random.random()<0.5 and vec[i]>range_list[i][0]:
        return vec[0:i] + [vec[i]-step] + vec[i+1:]
    elif vec[i]<range_list[i][1]:
        return vec[0:i] + [vec[i]+step] + vec[i+1:]
    
    # 遗传算法主函数
    # step是变异的幅度
    # popsize是种群大小,vote是种群中应该留下不淘汰的比例
    # generation是算法需要运行的代数,mix是种群中变异产生的概率
    def gene_op(range_list, cost_func, step=1, popsize=50, vote=0.2, generation=100, mix=0.2):
    dimension = len(range_list)
    
    # 初始化种群
    population = []
    for i in range(popsize):
        vec=[random.randint(range_list[j][0], range_list[j][1]) for j in range(dimension)]
        population.append(vec)
    
    top = popsize*vote  # 每一代中应该留下的数量
    
    for i in range(generation):
        # 计算出种群中的解的cost并排序
        cost_list = [(cost_func(vec), vec) for vec in population]
        cost_list.sort()
        para_list = [vec for (cost, vec) in cost_list]
        # 更新种群,选出最优的top个解添加进新种群
        population = para_list[0:top]
    
        # 往新种群中添加变异和交叉所产生的后代
        while len(population):
            if random.random()<mix:
                # 进行变异操作
                vec = para_list[random.randint(0, top)]  # 选出要变异的已在解
                population.append(alter(vec, range_list))
            else:
                # 进行交叉操作
                vec1 = para_list[random.randint(0, top)]  # 选出要交叉的最优解
                vec2 = para_list[random.randint(0, top)]
                population.append(crossover(vec1, vec2, dimension))
        # 打印出目前的最优解
        print para_list[0]
    # 返回最优解和最优解对应的目标函数值
    return population[0], cost_func(population[0])

如果对遗传算法还觉得不够了解,可以参考一下一篇博客:<>。这篇文章讲的很不错,对理解遗传算法思路很有帮助。

全部评论 (0)

还没有任何评论哟~