遗传算法原理案例及MATLAB代码

遗传算法的原理

  遗传算法的科学严谨的原理都在百度百科(遗传算法地址)中由详细解释,在这里我只表达我所理解的遗传算法原理。
 之所以叫遗传算法,原因是该算法是根据大自然中生物体进化规律而设计提出的,通过计算机的方法模拟自然进化过程搜索最优解。
遗传在百度百科中的解释:是指亲代表达相应性状的基因通过无性繁殖或有性繁殖传递给后代,从而使后代获得其父母遗传信息的现象。基因就是染色体,计算机方法也就是通过模拟染色体的行为来求得最优解。遗传算法对染色体的模拟主要是交叉和变异。

交叉

  在染色体中就是染色体片段的互换,可能是与其他个体交叉,也可能是本身的染色体交叉互换,每次交叉互换就会得到两个新的个体,从而得到两个个新的群体。
染色体交叉

变异

在这里的变异并不是缺失、重复、倒位、易位,而是在群体中的个体串的某些基因座上的基因值作变动,如下图所示:

在这里插入图片描述
 将原群体进行变异操作,又得到一个新的群体。

计算适应度

  完成以上染色体的行为的步骤后,就产生了新的三个群体。然后进行发育,就是用获得的基因,通过一定的计算得到相对应的结果,在生物的角度看,就是从受精卵发育成一个完整个体。在遗传算法中也就是计算适应度。

选择操作

 现在我们就有四个群体,交叉得到的两个群体,变异得到的一个群体,和原来的群体。计算适应度后,择优选择。
 不断重复以上操作,最终得到最优秀的群体。

遗传算法的案例

  以 f ( x ) = x sin ⁡ ( x ) cos ⁡ ( x ) f(x)=x\sin(x)\cos(x) f(x)=xsin(x)cos(x)为例,下图就是 f ( x ) , ( x ∈ [ 0 , 2 π ] ) f(x),(x\in[0,2\pi]) f(x),(x[0,2π])的图例:
在这里插入图片描述
 我们最终的目标是得到的该段函数的最大值,由图可以很容易看出来这个最大值的横坐标就是 x = 4 x=4 x=4附近,如下图所示:
在这里插入图片描述
 虽然我们可以直观的看出来最大值,可是是用一般算法可能会陷入局部最优,也就是最后的结果可能是横坐标 x = 1 x=1 x=1的点取值。因此,我们使用遗传算法来求解这个问题。
在这里插入图片描述

初始化种群

 如上图所示我们需要先初始化种群,也就是产生第一代个体,第一代个体的产生是随机的,在这里,我使用的是十进制编码去模拟基因,也可以用二进制编码,但是二进制编码的精度感觉没有十进制高。模拟的基因长度是5,随机产生多个基因,如下表随机产生的基因:

第一代的个体9 3 4 6 87 6 9 0 73 0 8 2 6

 现在可能有的同学有些疑问,为啥这一串数字就是基因呢?
 从基因的角度上说基因其实就是由携带了一定信息的DNA构成的,而这串数字也携带了一些信息。但是这个可能还是有点抽象,这是因为就算直接看真正的基因也是看不出什么东西来的,只有长成个体后,才知道这段基因决定了那些性状,就像高中课本中果蝇的不同表现型一样。现在我们就需要让这串基因“长大”,看看这串基因代表什么。
 由于我们使用的是十进制编码,所以,我们需要用到十进制编码器 [ 10000 ; 1000 ; 100 ; 10 ; 1 ] [10000; 1000; 100; 10 ;1] [10000;1000;100;10;1],以第一个个体基因9 3 4 6 8为例:

计算自适应度

 首先需要解码,就是将9 3 4 6 8与解码器 [ 10000 ; 1000 ; 100 ; 10 ; 1 ] [10000; 1000; 100; 10 ;1] [10000;1000;100;10;1]相乘相加,再相除对应的数:
9 × 10000 + 3 × 1000 + 4 × 100 + 6 × 10 + 8 × 1 = 93468 9\times10000+3\times1000+4\times100+6\times10+8\times1=93468 9×10000+3×1000+4×100+6×10+8×1=93468
x 1 = 93468 ÷ ( 9999 × 2 × π ) = 5.8728 x_1= 93468\div(9999\times2\times\pi)=5.8728 x1=93468÷(9999×2×π)=5.8728
 之所以除9999,是因为十位编码范围为 [ 0 , 9999 ] [0,9999] [0,9999],再除 2 π 2\pi 2π,是因为这是 x x x的取值范围。再将 x 1 = 5.8728 x_1=5.8728 x1=5.8728带入 f ( x ) f(x) f(x),得 f ( x 1 ) = − 2.1484 f(x_1)=-2.1484 f(x1)=2.1484,也就是说9 3 4 6 8这串基因最后的表现型是 − 2.1484 -2.1484 2.1484。如下图所示:
在这里插入图片描述
 我们生成20个个体,如下图所示:
在这里插入图片描述
 以上的步骤实际上就是计算自适应度(我也不知道为啥叫自适应度,可能还是知识浅薄😂)。

选择操作

 选择操作就是选择优秀的个体,在本案例中,说白了就是比大小,就拿刚刚算出的数 f ( x 1 ) = − 2.1484 f(x_1)=-2.1484 f(x1)=2.1484来看,这个数明显比较小,所以说明这个个体不咋滴,要排除。我们还看到有两个点已经很接近最大值了,那么说明这两个个体就比较优秀,于是就需要选择这两个个体。但在实际操作中也不是这样直接选择,因为可能会陷入局部最优,就比如都在 x = 1 x=1 x=1附近。因此,为了避免局部最优的情况发生,一般选用两种方法,一是轮盘赌法,二是排名法。
 轮盘法是通过每个个体与总体的适应度占比来衡量其优劣,比值越大越不容易被淘汰,就是将所有的个体的适应度累加,除以各个个体的适应度 P i = R i ∑ R i P_i={R_i \over\sum{R}_i} Pi=RiRi,其中 R i R_i Ri是各个个体的适应度。
 排名法是通过每个个体的适应度排名来看的,排名越靠前越不容易被淘汰,排名法的计算法复杂度相对较低,假设 f ( x 1 ) = − 2.1484 f(x_1)=-2.1484 f(x1)=2.1484是第15名,那么 p 1 = 15 20 = 0.75 p_1={15\over20}=0.75 p1=2015=0.75,就是有 75 % 75\% 75%的概率被移除。
 第一代种群生成后一般不进行选择操作。

交叉操作

 交叉操作就是基因片段的交换,设 D 1 = 93468 , D 2 = 76907 D_1=9 3 4 6 8,D_2=7 6 9 0 7 D1=93468,D2=76907,他们进行交叉,就是基因片段的互换,如下图所示:
在这里插入图片描述
 除了和其他个体交叉,也可能自己与自己交叉。交叉的对象都是随机的,这样做的目的都是为了让群体具有多样性,避免局部最优。

变异操作

 还是以 D 1 = 93468 D_1=9 3 4 6 8 D1=93468为例,每个数字可能会变成0~9,的任意一个数: 93460 , 93478 , . . . 93460,93478,... 9346093478...当然在生物界的实际情况也可知变异的概率较小,且变异的长度较短。
 通过以上操作,产生四个群体,再经选择操作,选出最优秀的20个。

MATLAB

clear,clc;
syms x
f = @(x) x.*sin(x).*cos(x)
ezplot(f, [0, 2*pi]) 
xlabel('x')
ylabel('y')

N = 20;                          % 种群上限
ger = 100;                       % 迭代次数
L = 5;                           % 基因长度
pc = 0.8;                        % 交叉概率
pm = 0.1;                        % 变异概率
dco = [10000; 1000; 100; 10 ;1]; % 解码器
dna = randi([0, 9], [N, L]);     % 基因
hold on
x = dna * dco / 99999 * 2 * pi;  % 对初始种群解码
plot(x, f(x),'ko','linewidth',3) % 画出初始解的位置

x1 = zeros(N, L);                % 初始化子代基因,提速用
x2 = x1;                         % 同上
x3 = x1;                         % 同上
fi = zeros(N, 1);                % 初始化适应度,提速

for epoch = 1: ger               % 进化代数为100
    for i = 1: N                 % 交叉操作
        if rand < pc
           d = randi(N);            % 确定另一个交叉的个体
           m = dna(d,:);            % 确定另一个交叉的个体
           d = randi(L-1);          % 确定交叉断点
           x1(i,:) = [dna(i,1:d), m(d+1:L)];  % 新个体 1        
           x2(i,:) = [m(1:d), dna(i,d+1:L)];  % 新个体 2
        end
    end
    x3 = dna;
    for i = 1: N                           % 变异操作
        if rand < pm
            x3(i,randi(L)) = randi([0, 9]);
        end
    end
    dna = [dna; x1; x2; x3];               % 合并新旧基因
    fi = f(dna * dco / 99999 * 2 * pi);    % 计算适应度,容易理解
    dna = [dna, fi];
    dna = flipud(sortrows(dna, L + 1));    % 对适应度进行排名
    while size(dna, 1) > N                 % 自然选择
        d = randi(size(dna, 1));           % 排名法
        if rand < (d - 1) / size(dna, 1)
            dna(d,:) = [];
            fi(d, :) = [];
        end
    end
    dna = dna(:, 1:L);
end
x = dna * dco / 99999 * 2 * pi;            % 对最终种群解码
plot(x, f(x),'ro','linewidth',3)           % 画出最终解的位置
disp(['最优解为x=',num2str(x(1))]);
disp(['最优值为y=',num2str(fi(1))]);


此代码不是我自己编的,原文链接:https://blog.csdn.net/nightmare_dimple/article/details/74355510

结果如下:

在这里插入图片描述

  • 7
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

会学习的小朋友

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值