02遗传算法

遗传算法原理

  • 遗传算法的难点,我认为集中在抽象过程的编码。遗传算法对问题的编码过程有实数值编码和二进制编码。两种编码方式。
  • 遗传算法具体实施有三个步骤:1,选择;2,交叉;3,变异。用自己的话把这三个步骤描述一下,如下:
    • 1,选择操作,根据物竞天择适者生存的法则,种群最终得以生存的多数个体的基因相对来说都很优良,身强体壮。这个选择操作就是根据个体适应度函数值进行排序。假设种群数量为n,则选择操作就要求选出适应度最好的前k个个体。
    • 2,交叉操作,就是高中的染色体碱基对配对。数学描述是说,n维的两个解向量(两个个体),假设交叉概率为 P c P_c Pc,则n维的解向量有 n ∗ P c n*P_c nPc的解分量需要产生交叉。但并不是说解分量的位置一定是相同的,这个和碱基对配对不同,因为碱基对的位置是固定的。
    • 3,变异操作,假设变异概率是 P m P_m Pm,则有 n ∗ P m n*P_m nPm的解分量按照一定的规则发生改变。

遗传算法生物学术语对照表

Alt

遗传算法流程图

在这里插入图片描述

仿真实例

跟前面的模拟退火算法一样,都是仿真第二个函数;
f ( x ) = ∑ i = 1 n x i 2 ( − 20 ⩽ x i ⩽ 20 ) f(x)=\sum_{i=1}^{n} x_{i}^{2}\left(-20 \leqslant x_{i} \leqslant 20\right) f(x)=i=1nxi2(20xi20)

Python实战

说明和感想

几乎每一行都有注释,所以不再解释;放在这里做分享。主要说明几点,相比较于书上给的例子,我这里做了几点改进:

1.书上以人为的方式强制迭代1000轮,而我是用精度控制的方式控制迭代次数;说人话就是书上的例子用for循环,我用的是while,因此实际上如果精度要求不高,完全不需要1000次迭代,0.001的精度500~600次就够了;

2.我的绘图比较好看,这个绘图真有意思,以后写论文用得到;

3.书上的代码,染色体基因做交叉时,用的君主方式配对交叉,但是不做判断不管好坏都交叉;虽然经过实验发现也能收敛,但是加上条件判断之后,更稳定。至于为什么也能收敛,而且效果不错。我不知道,可能任务太简单了。遇上复杂任务,不做条件的做交叉,会有更大概率陷入局部最优,这部分可以做改进。可以和模拟退火算法融合,用模拟退火算法概率接受差值解的方式扩充搜索空间。

import numpy as np
import matplotlib.pyplot as plt
import matplotlib
from numpy import random
class GA:
    def __init__(self,D,NP,Xs,Xx,E,Pc,Pm):
        '''
        参数初始化
        :param D:解维度
        :param NP: 解数量
        :param Xs: 解上限
        :param Xx: 解下限
        :param G: 迭代次数
        :param Pc: 交叉概率
        :param Pm: 变异概率
        '''
        self.D = D
        self.NP = NP
        self.Xs = Xs
        self.Xx = Xx
        self.E = E
        self.Pc = Pc
        self.Pm = Pm

    def func(self,x):
        return sum(x**2)

    def ga(self):
        # 初始化解空间
        x = random.rand(self.NP,self.D)*(self.Xs-self.Xx)+self.Xx
        # 计算适应度
        y = self.func(x.T)
        yk = np.sort(y) # 排序初始解的适应度
        # 取下标
        k = np.argsort(y)
        # 解空间排序
        xk = x[k]
        # 验证排序后的解计算的适应度是否与排序后的yk相等
        # y1 = self.func(xk.T)==yk
        # return y1 # 正确

        trace = []  # 记录最优适应度
        trace.append(yk[0])
        number = 0
        while True:
            # 采用君主方案选择交叉
            emperor = xk[0]
            cross_num = round(self.Pc*self.D)
            cross_loc = random.randint(0,10,(int(self.NP/2),self.D))
            nx = xk.copy() # 复制一份数组,生成新的内存空间;这里不做拷贝,全错
            odd = [i for i in range(self.NP) if (i+1)%2==1] # 奇数位下标
            nx[odd] = emperor # 奇数位置染色体全部赋予初始解的最优
            even = [i for i in range(self.NP) if (i+1)%2==0] # 偶数位下标
            # 做交叉操作
            '''
            前一个奇数位置和后一个偶数位置位一对,每一对需要做的交叉操作有cross_num次;
            这里有个改进,交叉之前判断交叉点是不是优解;不是则不交叉
            '''
            N = int(self.NP/2)
            for n in range(N):
                for num in range(cross_num):
                    k1 = odd[n]
                    k2 = even[n]
                    k3 = cross_loc[n,num]
                    k4 = nx[k1,k3]
                    k5 = nx[k2,k3]
                    k6 = emperor[k3]

                    if abs(k5) < abs(k4):  # 奇数位解分量比偶数位解分量大才交换
                        nx[odd[n], cross_loc[n, num]] = nx[even[n],cross_loc[n,num]]
                    if abs(k5) > abs(k6):  # 同理偶数位解分量比奇数位解分量大才交换
                        nx[even[n], cross_loc[n, num]] = emperor[cross_loc[n, num]]

                    # nx[odd[n], cross_loc[n, num]] = nx[even[n], cross_loc[n, num]]
                    # nx[even[n], cross_loc[n, num]] = emperor[cross_loc[n, num]]


            # 变异操作
            r = []
            for i in range(self.NP*self.D):
                r.append(True if np.random.rand() < self.Pm else False)
            r = np.array(r)
            r = r.reshape(self.NP,self.D)
            p = []
            for i in range(np.sum(r == True)):
                p.append(np.random.rand()*(self.Xs-self.Xx)+self.Xx)
            p = np.array(p)
            nx[r] = p
            # 计算子代适应度
            ny = self.func(nx.T)
            # 合并种群并排序
            x_sum = np.concatenate((nx,xk))
            y_sum = np.concatenate((ny,yk))
            rank_y = np.sort(y_sum) # 适应度重排
            nk = np.argsort(y_sum)
            rank_x = x_sum[nk] # 解空间重新排序
            xk = rank_x[:self.NP] #取前NP个最优解
            yk = rank_y[:self.NP] #取前NP个最适应度
            trace.append(yk[0])
            a = trace[number]
            b = trace[number+1]

            # if abs(b-a) < self.E:  # 精度控制方式1,比较差
            #     break
            if yk[0] < self.E:  # 精度控制方式2,更好
                break
            else:
                number += 1

        return trace ,xk

    def drawer(self):
        y, x = self.ga()
        plt.rc('legend', fontsize=16)
        matplotlib.rcParams['font.family'] = 'Kaiti'
        fig = plt.figure(figsize=(12,6),dpi=100)
        plt.plot(y, 'b:d', markerfacecolor='red',markersize=3,linewidth=1.5, label='遗传算法仿真重写和改进2')  # 1.线型颜色、线型风格、标记风格;2.线宽 3.标记颜色填充
        plt.xlabel('迭代次数', fontproperties='Kaiti', fontsize=14)  # 坐标轴标签设置
        plt.ylabel('适应度函数值', fontproperties='Kaiti', fontsize=14)
        plt.legend() # 添加图例
        # 图题
        plt.title(r'遗传算法求解$f(x)=\sum_{i=1}^{n} x_{i}^{2}\left(-20 \leqslant x_{i} \leqslant 20\right)$',
                  fontproperties='Kaiti', fontsize=14)
        plt.grid(True) # 网格
        plt.show()

ga = GA(10,100,20,-20,0.009,0.8,0.1)
ga.drawer()
y,x = ga.ga()
print(x[0],y[-5:])
实验结果
  • 由于仿真函数很简单,遗传算法用20步就可以找到最优解了。
    Alt
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值