python简易实现遗传算法求函数极值

基本思想

遗传算法(Genetic Algorithm, GA)
顾名思义是模仿生物的遗传学机理进行计算模拟最优解的过程。
将生物种群特征与问题进行对应
一个染色体代表问题的一个解(一个染色体含有多个基因)
一个基因代表问题的一个决策变量
多个个体构成一个种群,多组解构成解的种群。
我们使问题解的种群不断的优胜劣汰,像自然界的自然选择一般,直到最后剩下一个获胜的最优解,便结束了问题的求解。

算法流程

1. 初始化

随机生成一个种群。其中基因需要编码。
常用的编码方式有二进制编码法,浮点编码法,符号编码法。
今天先来做个二进制编码法,其解码、编码、交叉、变异等操作简单易行,但是由于随机性,局部搜索能力较差。
“与人类的染色体不同,我们假设只有“0”和“1”两种碱基,因此只需要将我们的决策变量进行二进制编码即可获得基因序列。”

2. 评估个体适应度

可以直接用函数值作为适应度,我们要找最小值嘛。

3. 进行自然选择

  • 计算出适应度综合 Σ f i \Sigma f_i Σfi
  • 计算出相对适应度大小 f i / Σ f i f_i/\Sigma f_i fi/Σfi
  • 产生随机出,确定各个个体被选中的次数

4. 进行组合交叉

选定一个交配概率pc

  • 群体随机配对
  • 随机设定交叉点
  • 互换染色体部分基因

5. 进行变异

  • 随机产生变异点
  • 根据变异概率阈值pm使原有基因突变
    python简易实现遗传算法求函数极值_第1张图片

终止条件

可以设置若干迭代次数作为终止条件。

目标问题

emmm,是在csdn的必问上看到一个问题,要求寻找目标函数的全局最小值
python简易实现遗传算法求函数极值_第2张图片
就打算拿这个试一下

算法实现

初始化

首先初始化种群,如果是n维输入的话,每个染色体上都应该有n个基因,分别代表 x 1 . . . . . x n x_1.....x_n x1.....xn
这个时候需要先考虑一些如何进行二进制编码。
x的范围是-32.77到32.77,我选用13位二进制数来编码。

将一个二进制串代表的二进制数转化为十进制数:
( b 0 . . . . . . b n ) = ( Σ i = 0 n b i 2 i ) = x ′ (b_0......b_n)=(\Sigma^n_{i=0}b_i2^i)=x' (b0......bn)=(Σi=0nbi2i)=x
对应区间内的实数:
x = − 32.77 + x ′ 65.54 2 13 − 1 x = - 32.77 + x'\frac{65.54}{2^{13}-1} x=32.77+x213165.54
那么有还原的函数

def translation(L):#将二进制编码还原为变量
    n = 0
    for i in range(13):
        n += L[i]*pow(2,i)
    
    return -32.77 + n * (65.54/k)

适应度函数与自然选择

这里用比较简单的选择方法,每个个体被选中的概率都是自身的适应度除以总适应度的和。
α i = F i Σ F \alpha_i = \frac{F_i}{\Sigma F} αi=ΣFFi
直接使用我们的目标函数,emmm好像不太成,这样的话越小的值适应度越小了,理论上应该是适应度越大才对。

def f(x):#目标函数
    n = len(x)
    return -20*np.exp(-0.2*np.sqrt(1/n*sum(np.power(x,2))))\
        -np.exp(1/n*sum(np.cos(2*pi*x))) + 20

不过那也好说,我们可以找出来所有个体的最大值,然后用这个值减去各个个体的函数值作为其适应度,这样最大的一个的适应度就是0,自然死亡。

def fitness(popular):
    fit = [0] * len(popular)
    n = len(popular[0])//13 #数据维度
    maxfit = -1e5
    for i in range(popular):
        x = []
        for j in range(n):
            x.append(translation(i[j:j+13]))
        fit[i] = f(np.array(x))
        if fit[i] > maxfit:
            maxfit = fit[i]
    for i in range(len(fit)):
        fit[i] = maxfit - fit[i]
    return fit

接下来就是轮盘赌了,计算出所有的适应度然后根据概率判断新的种群中的个体


def choose(popular):#进行自然选择
    popular_len = len(popular)#个体个数
    survival_rate = []
    for i in range(popular_len):
        survival_rate.append(random.random())
    
    fit = fitness(popular)#每个个体的存活率
    best_individual = popular[fit.index(max(fit))]#保存下当前种群最优个体(其实写这里不太会)
    survival_rate.sort()
    fitin = 0
    newin = 0
    newpopular = popular

    # 开始轮盘赌
    # 结束之后,适应度更高的个体在新种群中应该更多
    while newin < popular_len:
        if survival_rate[newin] < fit[fitin]:
            newpopular[newin] = popular[fitin]
            newin += 1#旋转轮盘
        else:
            fitin += 1#旋转轮盘
    popular = newpopular
    return best_individual

交叉

取交叉率pc=0.5

def crossover(popular,pc):#pc为交叉率
    popular_len=len(popular)

    for i in range(popular_len-1):
        crosspoint = random.randint(0,len(popular[0]))#随机生成交叉点
        # 一个个体染色体长度为len(popular[0]),crosspoint为交换位置
        #接下来我们让第i个个体和第i+1个个体发生交叉
        t1 =[]
        t2= []
        t1.extend(popular[i][0:crosspoint])#i的前半段
        t1.extend(popular[i+1][crosspoint:-1])#i+1的后半段
        t2.extend(popular[i+1][0:crosspoint])#i+1的前半段
        t2.extend(popular[i][crosspoint:-1])#i的后半段
        # 放回种群
        popular[i] = t1 
        popular[i+1] = t2

变异

取变异率0.01吧

def mutation(popular,pm):#pm为变异率
    popular_len=len(popular)
    chromosome_len = len(popular[0])
    for i in range(popular_len):
        if random.random()>pm:#大于阈值则发生变异
            mutation_point = random.randint(0,chromosome_len-1)
            #发生变异
            if popular[i][mutation_point] == 1:
                popular[i][mutation_point] = 0
            else:
                popular[i][mutation_point] = 1

最后连起来实现迭代

def GA(n):
    ## 初始化种群
    popular_size = 100#种群大小
    chromosome_length = n*13#染色体大小
    popular = []
    for i in range(popular_size):
        individual = []
        for j in range(chromosome_length):#生成随机基因
            individual.append(random.randint(0,1))
        popular.append(individual)#向种群添加一个个体
    # 种群初始化完成
    best_individual = []
    for i in range(200):#迭代200次
        best_individual.append( choose(popular) ) #保存下最优个体
        crossover(popular,0.5)
        mutation(popular,0.01)
    solutions = []#解的迭代过程
    for i in best_individual:
        s = []
        for j in range(n):
           s.append(translation( i[13*j:13*j+13] ))
        #还原为了十进制数   
        solutions.append(s)
    return solutions#保存的是各次迭代发现的最优解,最后一个是结果

代码

python代码

你可能感兴趣的:(python,算法,遗传算法)