经典遗传算法及MATLAB实例

article/2025/11/6 22:33:36

经典遗传算法及简单实例(MATLAB)

  • 1. 遗传算法简单介绍
    • 1.1 理论基础
    • 1.2 算法要点
      • 1.1 编码
      • 1.2 适应度函数
    • 1.3 基本流程
  • 2. 代码实例(MATLAB)
    • 2.1 代码汇总
    • 2.1 初始化种群
    • 2.2 计算适应度
    • 2.3 迭代终止判断
    • 2.4 自然选择(轮盘赌法)
    • 2.5 配对交叉(单点)
    • 2.6 变异(基本位变异)
    • 2.7 获得最优解
    • 2.8 雪兔遗传结果
    • 2.9 改善遗传算法的方法
  • 3. 多多交流!

1. 遗传算法简单介绍

1.1 理论基础

整个算法的基础就是达尔文的生物进化论,“物竞天择,适者生存” 这句话已经是常识了。

用雪兔做一个引子吧:

东北那旮瘩,有群原始雪兔,刚从未知物种进化而来,五颜六色(表现型)漂亮极了,称之为 I(0)。
(注意:种群初始化)

入夏了,雪兔们出来觅食,浅色兔在草地中无所遁形,被雪狐收割了一波(大批浅色+小批深色)。
入冬了,雪兔们出来觅食,深色兔在雪地中光彩夺目,被雪狐收割了一波(大批深色+小批浅色)。
(注意:自然选择过程)

春天到了,又到了兔兔们生孩的季节,雪兔们染色体内的基因进行 重组/不重组 ,产生一批受精卵。
(注意:交叉遗传过程)

受精卵内的生命活动非常强烈,造成了基因的 突变/不突变,产生了各种各样奇怪的小雪兔。
(注意:基因变异过程)

老雪兔们完成了自己繁衍的使命,全部不知所踪。留下新生代,继续在各种威胁下苟活,这一代叫 I(1)。

再次入冬入夏,雪兔们又出来觅食。。。。。。再次入冬,觅食。。。。。。入冬,觅食。。。。。。

就这样,50年后,基因突变和重组造就了种神奇的兔子:夏天褐色,冬天白色,可以轻易躲避雪狐的追捕

再次入冬入夏,雪兔们又出来觅食。。。。。。再次入冬,觅食。。。。。。入冬,觅食。。。。。。

这样,50年后,雪地里基本上见不到五颜六色的雪兔了,这时候雪兔们达到了兔生巅峰!

这就是遗传算法的理论基础,自然选择、交叉、变异、迭代,最终获得最优解。

注意:算法是根据表现型来进行选择,最终选出最优的表现型及其对应的基因。

1.2 算法要点

1.1 编码

编码是为了把我们的输入参数变成染色体(每个个体只有一条染色体),以便于进行交叉和遗传运算。

例如我们把雪兔的颜色进行划分, 0-255 (表现型)代表 黑->白 的不同程度,0就是纯黑的,255就是纯白的。

我们这里只谈一下简单的二进制编码,二进制编码中的每一个二进制位是一个基因,整个数字为染色体。

那么0-255共有256阶(表现型),我们可以用8位2进制数来表示(基因型)。

兔色为0的编码为 00000000,兔色为2的编码为 00000010,兔色为255的编码为 11111111。

1.2 适应度函数

适应度函数就是个体对环境的适应度,适应度越强的越能产生后代,保留自己的基因及表现型。

这里,我们假设灰色兔子的适应能力最强,即兔色为128的兔子不会被吃掉,设定函数为:

在这里插入图片描述

是一个最大值为128的分段函数,图像如下:
在这里插入图片描述
适应度函数的极值点一般是未知的,这里我们为了演示方便,就先展示出来。

1.3 基本流程

流程就和雪兔故事一样简单,如下所示:

在这里插入图片描述

注意:迭代的终止条件可以不是最大迭代次数,比如规定为种群适应度值的方差小于某个值(即种群表现型趋于一致)。

2. 代码实例(MATLAB)

2.1 代码汇总

遗传算法代码(通用代码):

function [bestChromosome,fitnessBest]=GA(numOfChromosome,numOfGene,iterationNum)
%% 函数功能:执行基于自适应遗传算法的卸载决策
%   输入:
%       numOfChromosome:染色体数量,即迭代的种群大小
%       numOfGene:基因的数量,即所用二进制编码的位数
%       iterationNum:迭代的总次数,达到迭代次数即终止迭代
%   输出:
%       bestChromosome:最优的染色体(即最优的输入)
%       fitnessBest:最优的适应度值(即最优的结果)%% 随机生成初始种群,种群大小为numOfChromosome,染色体中基因数为numOfGene
% lastPopulation:上一代的种群(染色体)
% newPopulation:新一代的种群(染色体)
% randi([0,1])会产生0或1的整数
lastPopulation=randi([0,1],numOfChromosome,numOfGene);
newPopulation=zeros(numOfChromosome,numOfGene);%% 进行遗传迭代,直至达到最大迭代次数iterationNum
for iteration=1:iterationNum%% 计算所有个体(染色体)的适应度,一共有numOfChromosome个适应度值fitnessAll=zeros(1,numOfChromosome);for i=1:numOfChromosomeindividual=lastPopulation(i,:);fitnessAll(i)=fitnessFunc(individual);end%% 如果达到最大迭代次数,跳出(不能再进行选择遗传和变异了)if iteration==iterationNumbreak;end%% 使用轮盘赌法选择numOfChromosome条染色体,种群中个体总数不变fitnessSum=sum(fitnessAll);fitnessProportion=fitnessAll/fitnessSum;% 使用随机数进行numOfChromosome次选择,保持种群中个体数量不变for i=1:numOfChromosomeprobability=rand(1);proportionSum=0;chromosomeIndex=1;for j=1:numOfChromosomeproportionSum=proportionSum+fitnessProportion(j);if proportionSum>=probabilitychromosomeIndex=j;break;endendnewPopulation(i,:)=lastPopulation(chromosomeIndex,:);end%% 将染色体进行配对,执行单点交叉lastPopulation=newPopulation;% 生成从1到numOfChromosome的无序排列,每两个相邻数字进行配对coupleAllIndex=randperm(numOfChromosome);for i=1:floor(numOfChromosome/2)coupleOneIndex=coupleAllIndex(2*i-1:2*i);% 定义两条染色体交叉的概率,自己选择probability=0.6;% 如果生成的随机数在交叉概率内,执行交叉操作if rand(i)<probability% 随机生成交叉的基因点,将两条基因进行交叉crossPosition=randi([1,numOfGene],1);newPopulation(coupleOneIndex(1),crossPosition:end)=lastPopulation(coupleOneIndex(2),crossPosition:end);newPopulation(coupleOneIndex(2),crossPosition:end)=lastPopulation(coupleOneIndex(1),crossPosition:end);endend%% 对每条染色体执行基本位变异操作lastPopulation=newPopulation;for i=1:numOfChromosome% 定义染色体变异的概率,自己选择probability=0.2;% 如果生成的随机数在变异概率内,执行变异操作if rand(1)<probability% 选择变异的位置mutatePosition=randi([1,numOfGene],1);% 将对应基因位置的二进制数反转if(lastPopulation(i,mutatePosition)==0)newPopulation(i,mutatePosition)=1;elsenewPopulation(i,mutatePosition)=0;endendend %% 完成了一次迭代,更新种群lastPopulation=newPopulation;
end%% 遗传迭代结束后,获得最优适应度值和对应的基因
fitnessBest=max(fitnessAll);
bestChromosome=newPopulation(find(fitnessAll==fitnessBest,1),:);

雪兔例子的适应度计算代码:

function fitness=fitnessFunc(chromosome)
%% 函数功能:计算染色体的表现型及其适应度
% 输入:
%       chromosome:染色体的基因序列
% 输出:
%       fitness:染色体(个体)的适应度值%% 计算雪兔染色体对应表现型
len=length(chromosome);
numList=2.^(len-1:-1:0);
x=sum(chromosome.*numList);%% 计算表现型对应的适应度
if x<128fitness=x;
elseif x>128fitness=256-x;elsefitness=128;end
end

2.1 初始化种群

%% 随机生成初始种群,种群大小为numOfChromosome,染色体中基因数为numOfGene
% lastPopulation:上一代的种群(染色体)
% newPopulation:新一代的种群(染色体)
% randi([0,1])会产生0或1的整数
lastPopulation=randi([0,1],numOfChromosome,numOfGene);
newPopulation=zeros(numOfChromosome,numOfGene);

这里使用随机数生成函数生成了numOfChromosome条染色体,每条染色体有numOfGene个基因。

将生成的种群放入lastPopulation中,每一行是一条染色体。

newPopulation相当于一个辅助数组,存储生成种群的中间结果。

2.2 计算适应度

    %% 计算所有个体(染色体)的适应度,一共有numOfChromosome个适应度值fitnessAll=zeros(1,numOfChromosome);for i=1:numOfChromosomeindividual=lastPopulation(i,:);fitnessAll(i)=fitnessFunc(individual);end

计算种群中所有个体的适应度,即把每一条染色体(个体)都放入适应度函数中,得到适应度结果。

2.3 迭代终止判断

    %% 如果达到最大迭代次数,跳出(不能再进行选择遗传和变异了)if iteration==iterationNumbreak;end

计算完适应度,如果达到终止条件,就不再进行选择、遗传和变异了。

否则你跳出循环时,种群适应度与计算的的适应度不匹配。

另一种方案:执行选择、遗传、变异,跳出循环后再次计算适应度即可。

2.4 自然选择(轮盘赌法)

    %% 使用轮盘赌法选择numOfChromosome条染色体,种群中个体总数不变fitnessSum=sum(fitnessAll);fitnessProportion=fitnessAll/fitnessSum;% 使用随机数进行numOfChromosome次选择,保持种群中个体数量不变for i=1:numOfChromosomeprobability=rand(1);proportionSum=0;chromosomeIndex=1;for j=1:numOfChromosomeproportionSum=proportionSum+fitnessProportion(j);if proportionSum>=probabilitychromosomeIndex=j;break;endendnewPopulation(i,:)=lastPopulation(chromosomeIndex,:);end

计算每个个体适应度占总适应度的比例,总适应度是一个饼图,每个个体占据一定的扇形区域。

在这里插入图片描述

然后生成numOfChromosome个0-1的随机数,随机数落在哪个区域,哪个个体便被生存,可重复选择。

显然,适应度高的个体容易被选择,将自己的基因和表现型遗传下去。

2.5 配对交叉(单点)

    %% 将染色体进行配对,执行单点交叉lastPopulation=newPopulation;% 生成从1到numOfChromosome的无序排列,每两个相邻数字进行配对coupleAllIndex=randperm(numOfChromosome);for i=1:floor(numOfChromosome/2)coupleOneIndex=coupleAllIndex(2*i-1:2*i);% 定义两条染色体交叉的概率,自己选择probability=0.6;% 如果生成的随机数在交叉概率内,执行交叉操作if rand(i)<probability% 随机生成交叉的基因点,将两条基因进行交叉crossPosition=randi([1,numOfGene],1);newPopulation(coupleOneIndex(1),crossPosition:end)=lastPopulation(coupleOneIndex(2),crossPosition:end);newPopulation(coupleOneIndex(2),crossPosition:end)=lastPopulation(coupleOneIndex(1),crossPosition:end);endend

进行遗传的前提是配对,每两条染色体组合成一对,将两者的部分染色体进行交换。

单点交叉,顾名思义,选择染色体上的一个基因点,从这个基因点开始的两条染色体片段互换:

在这里插入图片描述

2.6 变异(基本位变异)

    %% 对每条染色体执行基本位变异操作lastPopulation=newPopulation;for i=1:numOfChromosome% 定义染色体变异的概率,自己选择probability=0.2;% 如果生成的随机数在变异概率内,执行变异操作if rand(1)<probability% 选择变异的位置mutatePosition=randi([1,numOfGene],1);% 将对应基因位置的二进制数反转if(lastPopulation(i,mutatePosition)==0)newPopulation(i,mutatePosition)=1;elsenewPopulation(i,mutatePosition)=0;endendend 

基本位变异就是选择一条染色体上的一个基因点,将其取反。

如染色体 11111111,选择其第四个基因进行基本位变异, 新染色体变为 11101111

2.7 获得最优解

%% 遗传迭代结束后,获得最优适应度值和对应的基因
fitnessBest=max(fitnessAll);
bestChromosome=newPopulation(find(fitnessAll==fitnessBest,1),:);

迭代结束之后,我们求出最大的适应度及其对应的染色体(个体),这就是我们需要的最优个体。

2.8 雪兔遗传结果

我们运行2.1给出的GA函数,在命令行输入以下代码运行:

[bestChromosome,fitnessBest]=GA(40,8,60)

40个染色体进行60次迭代。多次这行代码,发现结果可以不同,如下:
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
虽然结果不尽相同,但都接近最优解128,这是遗传算法本身的局限,不一定能获得最优解。

2.9 改善遗传算法的方法

通过2.8我们知道,遗传算法有时候只能逼近最优解,那么有什么方法能让他达到更好的逼近效果呢?

这里有几个方案:

  1. 使用自适应遗传和变异概率
  2. 增加种群中个体数量
  3. 增大迭代次数
  4. 使用双点交叉法
  5. 采用多样的变异方法
  6. 更改编码方式(某些情况)
  7. 更换适应度函数,将个体适应度的差距拉大
  8. 更换选择方法,轮盘赌法是最基本的方法,不科学

大家可以自行了解,以后可能会继续就这几个方面探讨。

3. 多多交流!


http://chatgpt.dhexx.cn/article/lirTHTRH.shtml

相关文章

遗传算法及实例

遗传算法是模拟生物在自然环境下遗传的过程而形成的自适应全局优化搜索算法。如果把某个问题的可行域看作是一个族群&#xff0c;目标函数看作是自然选择的条件&#xff0c;那么&#xff0c;这个族群通过一代又一代的繁衍和进化最终变成最接近筛选条件的样子。遗传算法就是利用…

遗传算法原理及算法实例

遗传算法原理解析 遗传算法&#xff08;GA&#xff09;是一种元启发式自然选择的过程&#xff0c;属于进化算法&#xff08;EA&#xff09;大类。遗传算法通常是利用生物启发算子&#xff0c;如变异、交叉和选择来生成高质量的优化和搜索问题的解决方案。 借鉴生物进化理论&…

遗传算法小结及算法实例(附Matlab代码)

目录 1、遗传算法流程 2、关键参数说明 &#xff08;1&#xff09;群体规模 \(NP\) &#xff08;2&#xff09;交叉概率 \(P_c\) &#xff08;3&#xff09;变异概率 \(P_m\) &#xff08;4&#xff09;进化代数 \(G\) 3、MATLAB仿真实例 3.1 遗传算法求解一元函数的极…

遗传算法(Genetic Algorithm,GA)实例详解

遗传算法是模拟生物在自然环境中的遗传和进化的过程而形成的自适应全局优化搜索算法&#xff0c;他能有效求解NP问题以及非线性、多峰函数优化和多目标优化问题。 1.理论基础 1.1生物学基础 遗传算法的生物学基础是借鉴了达尔文的进化论和孟德尔的遗传学说&#xff0c;一个种…

遗传算法设计实例

1.遗传算法实例程序设计 随机初始化种群P(t){x1,x2…xn),计算P(t)中个体的适应值。其MATLAB程序的基本格式如下: Begin t0 初始化P(t) 计算P(t)的适应值; while (不满足停止准则)dobegintt1从P(t1)中选择P(t)重组P(t)计算P(t)的适应值 end例1 求函数 f(x) 9*sin(5x) cos(4x)…

遗传算法GA原理详解及实例应用 附Python代码

遗传算法GA 遗传算法&#xff08;Genetic Algorithm, GA&#xff09;是模拟达尔文生物进化论的自然选择和遗传学机理的生物进化过程的计算模型&#xff0c;是一种通过模拟自然进化过程搜索最优解的方法。 生物在自然界中的生存繁衍&#xff0c;显示了其对自然环境的优异的自适…

vue实现点击下载exe,运行报错shellexecuteex失败 代码2

页面效果 exe插件放在vue项目的public文件夹里&#xff0c;然后用a标签实现点击下载 <a href"/VideoWebPlugin.exe">下载插件</a> 成功下载后运行报错 解决方法&#xff1a;选择在文件夹中显示&#xff0c;右击属性&#xff0c;在兼容性设置里的以管理员…

VC++分别使用WinExec、CreateProcess、ShellExecute和ShellExecuteEx来启动程序(附源码)

VC++常用功能开发汇总(专栏文章列表,欢迎订阅,持续更新...)https://blog.csdn.net/chenlycly/article/details/124272585C++软件异常排查从入门到精通系列教程(专栏文章列表,欢迎订阅,持续更新...)

API函数ShellExecute与ShellExecuteEx用法

ShellExecute: 1.函数功能:你可以给它任何文件的名字,它都能识别出来并打开它。2.函数原型: HINSTANCE ShellExecute( HWND hwnd, LPCTSTR lpOperation, LPCTSTR lpFile, LPCTSTR lpParameters, LPCTSTR lpDirectory, INT nShowCmd ); 3.参数说明:hwnd:用于指定父窗口句…

C/C++ 使用 API 函数 ShellExecuteEx 实现文件打印

本文章主要介绍使用ShellExecuteEx实现打印文件的功能。 函数原型&#xff1a;BOOL ShellExecuteExA(__inout SHELLEXECUTEINFOA *pExecInfo) 输入输出参数都是 SHELLEXECUTEINFO 结构体。 SHELLEXECUTEINFO定义&#xff1a; typedef struct _SHELLEXECUTEINFO { DWORD c…

Windows函数 ShellExecuteEx

点击进入视频教程 代码&#xff1a; #include<windows.h> #include<tchar.h> #pragma comment(lib, "Urlmon.lib") int WINAPI _tWinMain(HINSTANCE hinstance, HINSTANCE hPreInstance, LPTSTR lpCmdLine, int nShowCmd) {// 下载图片&#xff0c;并保…

UpdatePanel终于可以上传文件了!

我们要做的&#xff0c;只是在页面上添加一个控件而已。 不过&#xff0c;其实这只是个半成品&#xff0c;或者说是一个原型&#xff0c;但是很明显&#xff0c;我们做对了。:) 在实现上&#xff0c;我曾经在两个做法上斟酌了许久&#xff0c;第一种是继承ScriptManager&#x…

updatepanel 排版问题

使用 ASP.NET AJAX 開發人員&#xff0c;一定不會錯過 UpdatePanel 這個超級控制項&#xff0c;它可以讓輕易的讓原有設計的頁面很輕易的具有 AJAX 的效果。可是在設計階段使用 UpdatePanel 去排版常造成我們的困擾&#xff0c;放置在 UpdatePanel 中的控制項無法正確呈現實際的…

学习UpdatePanel控件-

原文可以显示图片&#xff08;转载&#xff1a;http://blog.csdn.net/ILOVEMSDN/archive/2007/11/11/1879343.aspx&#xff09; UpdatePanel控件的使用 2008-10-07 05:46 P.M. ScriptManager和UpdatePanel控件联合使用可以实现页面异步局部更新的效果。其中的UpdatePanel就是…

UpdatePanel的用法

UpdatePanel控件也是Ajax里用得最多的控件之中的一个&#xff0c;UpdatePanel控件是用来局部更新网页上的内容&#xff0c;网页上要局部更新的内容必须放在UpdatePanel控件里&#xff0c;他必须和上一次说的ScriptManager控件一起使用。如今来看UpdatePanel的属性 UpdatePanel …

浅谈UpdatePanel

这是我以前刚学习asp.net ajax的时候总结的&#xff0c;如果有什么错误的地方&#xff0c;请大家指出&#xff0c;以便我能早日改正。 1. 作用&#xff1a; UpdatePanel控件用来控制页面的局部更新&#xff0c;这些更新依赖于ScriptManager的EnablePartialRendering属性&…

UpdatePanel 控件简介

UpdatePanel 控件简介 全部折叠全部展开 代码&#xff1a;全部 代码&#xff1a;多种 代码&#xff1a;Visual Basic 代码&#xff1a;C# 代码&#xff1a;Visual C 代码&#xff1a;F# 代码&#xff1a;JScript UpdatePanel 控件简介 在本教程中&#xff0c;您将使用两…

ScriptManager updatepanel

在项目开发中&#xff0c;遇到了一个ajax更新问题&#xff0c;母版上有个通知区域&#xff08;通知区域为ajax定时更新&#xff08;updatepanel&#xff09;&#xff09;&#xff0c;上面有需要显示的几列信息&#xff0c;如最新文章数&#xff0c;批阅数&#xff0c;FTP受信状…

使用 UpdatePanel

1 概述 ASP.NET UpdatePanel 控件能让你创建丰富的、以客户为中心的 Web 应用程序。使用 UpdatePanel 控件&#xff0c;可以刷新选择的页面部分而不是使用回发来刷新整个页面&#xff0c;这就像是执行了一个局部页面更新一样。包含一个 ScriptManager 和一个或多个 UpdatePanel…

UpdatePanel控件

ASP.NET UpdatePanel控件可用于生成功能丰富、以客户端为中心的Web应用程序。通过使用UpdatePanel控件&#xff0c;可以在回发期间刷新网页的选定部分而不是刷新整个网页。这称为执行部分页更新。包含一个ScriptManager控件和一个或多个UpdatePanel控件的ASP.NET网页&#xff0…