Python遗传算法求一元函数最大值

Python遗传算法求一元函数最大值

    • 前言
    • 代码
    • 后记
    • 参考文献

前言

最近接触遗传算法,参考了众多例子,有些又不尽然对,所以自己边理解边修改,然后写出了下面这堆传说中的屎山。。。
PS1:遗传算法原理啥的太多了,就不赘述了,CSDN里面很多帖子都讲得很透彻了;
PS2:要看简洁的,直接油管搜遗传算法,看莫烦的视频。

代码

不废话了,赶紧上车,啊不,上代码。

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


class GA(object):
    # 目标求解2*sin(x)+cos(x)最大值
    def __init__(self, population_size, chromosome_length, pm):
        self.population_size = population_size
        self.chromosome_length = chromosome_length
        self.pm = pm

    # 初始化种群
    def species_origin(self):  # 生成染色体和基因
        population = [[]]  # 二维列表,包含染色体和基因
        for i in range(self.population_size):
            temporary = []  # 染色体寄存器
            for j in range(self.chromosome_length):
                temporary.append(random.randint(0, 1))  # 生成基因,二进制
            population.append(temporary)  # 将基因添加到染色体中
        return population[1:]  # 返回种群,包含染色体和基因

    # 种群解码,用于适应度判断
    def translation(self, population):  # 二进制转十进制
        chromosome_d_list = []  # 创建染色体十进制列表
        for i in range(len(population)):
            chromosome_value_d = 0
            for j in range(len(population[0])):
                chromosome_value_d += population[i][j] * (math.pow(2, len(population[0])-j-1))  
            chromosome_d_list.append(chromosome_value_d)  
        return chromosome_d_list

    # 适应度计算
    def function(self, population, lower_bound, upper_bound):
        all_fitness_list = []  # 创建所有染色体适应度列表
        fv_list = self.translation(population)
        for i in range(len(fv_list)):
            x = lower_bound + fv_list[i] * (upper_bound - lower_bound)/(math.pow(2, self.chromosome_length) - 1)
            y = 2 * math.sin(x) + math.cos(x)  # 目标函数
            all_fitness_list.append(y)  
        return all_fitness_list

    # 剔除适应度负值
    def positive_fitness(self, all_fitness_list):
        pf = []
        for i in range(len(all_fitness_list)):
            if all_fitness_list[i] > 0:
                pf.append(all_fitness_list[i])
        return pf

    # 正适应度染色体列表
    def positive_chromosome(self, all_fitness_list, population):
        positive_chromosome_list = []
        for i in range(len(all_fitness_list)):
            if all_fitness_list[i] > 0:
                positive_chromosome_list.append(population[i])
        return positive_chromosome_list

    # 计算正适应度总和
    def pf_sum(self, pf):
        pf_total = 0
        for i in range(len(pf)):
            pf_total += pf[i]
        return pf_total
	
	# 正适应度变为小数
    def pf_float(self, pf_total, pf):  
        pf_float = []
        for i in range(len(pf)):  # 正适应度除以适应度总数,转化为小数
            pf_float.append(pf[i] / pf_total)
        return pf_float

    # 适应度累加,为分区做准备
    def pf_div(self, pf_float):
        pft_div = []
        for j in range(len(pf_float)):  # 将适应度转化为轮盘赌的概率
            if j == 0:
                pft_div.append(pf_float[j])
            else:
                pft_div.append(pf_float[j] + pft_div[j-1])
        return pft_div

    # 选择
    def selection(self, pcl, pft_div):
        selected_pop = []  # 挑选后的新种群
        select_float = []  # 随机产生的小数
        for i in range(len(pcl)):  # 产生随机小数
            select_float.append(random.random())
        for i in range(len(pcl)):  # 轮盘赌选择
            j = 0
            while j < len(pcl):
                if select_float[i] <= pft_div[j]:  # 随机小数与适应度区间对比
                    selected_pop.append(pcl[j])
                    break
                else:
                    j += 1
        return selected_pop

    # 交叉
    def crossover(self, selected_pop, population):  # 单点交叉
        new_pop = [[]]  
        for i in range(len(population)):
            cpoint = random.randint(0, len(selected_pop[0]) - 1)  # 随机生成截取点 #
            while True:
                spoint1 = random.randint(0, len(selected_pop) - 1)
                spoint2 = random.randint(0, len(selected_pop) - 1)
                if spoint1 == spoint2:
                    continue
                else:
                    break
            temp = []  # 染色体片段暂时存储器
            temp.extend(selected_pop[spoint1][0:cpoint])  # 第i个染色体0~截取点阶段的基因存储于temp中
            temp.extend(selected_pop[spoint2][cpoint:len(selected_pop[0])])  # 第i+1个染色体截取点~末端阶段的基因存储于temp中
            new_pop.append(temp)
        return new_pop[1:]
    # 变异
    def mutation(self, new_pop):
        for i in range(len(new_pop)):  # 对所有染色体进行有概率的变异
            mpoint = random.randint(0, len(new_pop[0])-1)  # 根据染色体长度,随机生成变异的位数
            prandom = random.random()  # 随机生成[0,1)之间的小数作为比较概率
            if prandom <= self.pm:
                if new_pop[i][mpoint] == 1:
                    new_pop[i][mpoint] = 0
                else:
                    new_pop[i][mpoint] = 1
        next_pop = new_pop
        return next_pop

    # 二进制转十进制
    def b2d(self, value_b):
        pf_d = []
        for i in range(len(value_b)):
            value_d = 0
            for j in range(len(value_b[0])):
                value_d += value_b[i][j] * math.pow(2, len(value_b[0])-1-j)
            pf_d.append(value_d)
        return pf_d

	# 可视化
    def plot(self, pcl_d_list, pf, lower_bound, upper_bound, generation, iteration):
        px = []
        for i in range(len(pcl_d_list)):
            pxt = lower_bound + pcl_d_list[i] * (upper_bound - lower_bound) / (math.pow(2, self.chromosome_length) - 1)
            px.append(pxt)
        py = pf
        sca = plt.scatter(px, py, s=200, lw=0, c='red', alpha=0.5)  
        plt.pause(0.05)  
        print('px', len(px))
        j = generation
        if j < iteration-1:
            if 'sca' in locals():
                sca.remove()

    # 主程序
    def main(self, iteration):
        population = self.species_origin()  # 创建种群
        results = []
        for i in range(iteration):
            self.translation(population)  
            all_fitness_list = self.function(population, 0, 2*math.pi)  
            pf = self.positive_fitness(all_fitness_list)  
            pcl = self.positive_chromosome(all_fitness_list, population)  
            self.plot(self.translation(pcl), pf, 0, 2 * np.pi, i, iteration)
            #print('pcl', pcl)
            pf_total = self.pf_sum(pf)  
            pf_float = self.pf_float(pf_total, pf) 
            pft_div = self.pf_div(pf_float)  
            #print('pft_div', pft_div)
            selected_pop = self.selection(pcl, pft_div)  
            new_pop = self.crossover(selected_pop, population)  
            next_pop = self.mutation(new_pop)  
            population = next_pop  
            results.append(pf_total)
            print('The', i, 'generation pf:', pf, '\npf length', len(pf))

        plt.ioff() 
        plt.show()


if __name__ == '__main__':
    ga = GA(100, 17, 0.01)
    plt.ion()  
    x = np.linspace(0, 2*np.pi, 100)
    Fx = 2 * np.sin(x) + np.cos(x)
    plt.plot(x, Fx)
    plt.grid()
    ga.main(500)
    

后记

欢迎交流拍砖,但是瞎骂并不可取嗷~

参考文献

[1]: https://blog.csdn.net/b2b160/article/details/4680853.
[2]: https://blog.csdn.net/acelit/article/details/78187715.
[3]: https://blog.csdn.net/quinn1994/article/details/80501542.
[4]: https://blog.csdn.net/m0_38101326/article/details/90642193.
[5]: https://github.com/MorvanZhou/Evolutionary-Algorithm/blob/master/tutorial-contents/Genetic%20Algorithm/Genetic%20Algorithm%20Basic.py#L72.

你可能感兴趣的:(算法_Python)