遗传算法的代码实现
本章通过讲解一道例题,带大家介绍遗传算法如何用代码实现
一、问题提出
二、参数设置
NP为种群个体数,我们会在这么多数量的种群中进行基因的交换与变异。
惩罚系数是在计算适应度时用的,若我们的选择超出了适应度的范围,就把适应度减去一个比较大的数,而在实时脚本文件中,函数可以放在文件的最下面,这样就不用定义全局变量了
Np = 80; % 种群个体数
N = 12; % 物品数
V = 350; % 背包容量
Pc = 0.85; % 交叉概率
Pv = 0.02; % 变异概率
Gtime = 150; % 遗传代数(迭代次数)
C = [78,39,90,82,61,52,12,37,49,55,64,8]; % 物品体积
W = [64,37,22,41,76,34,22,21,10,57,32,12]; % 物品价值
alpha = 5; % 惩罚系数
二、开始迭代,种群初始化
我们先随机获得一个初始的种群,利用randi函数生成一个由0-1组成的,80行12列的矩阵。一行代表一个个体,行上面的数字代表基因
t=1:Gtime代表我们要在80个个体中迭代Gtime次
在循环的开始,我们先要计算出每个个体的适应度,找到出适应度最优的个体
population = randi([0,1],Np,N); %随机获得初始种群
% 开始迭代
for t = 1:Gtime
% 求每个个体的适应度
for i = 1:Np
fit(i) = fitness(population(i,:),C,W,V,alpha);
end
maxfit = max(fit); % 适应度最大值(本轮迭代最优解的函数值)
minfit = min(fit);
% find函数找到满足等式的元素(最优个体)下标(在群体里的序号是几),可能有多个
findex = find(fit == maxfit);
fBest = population(findex(1,1),:); % 根据序号选中最优个体
三、进行轮盘赌法,选中适应度大的个体
我们想要选择适应度大的个体进行基因交叉(对应自然界中强者才有资格交配),但是这里我们并没有直接给适应度大的个体排序(因为适应度大,基因可能也非常相似,从而一直陷入局部最优),而是利用轮盘赌法,使得适应度大的个体有更大的概率被选中,但适应度小的个体也有一定的概率被选中
这里我们的fitvalue的最大值是1,但我们生成的数组最大值到不了1(开区间),因此不会出现fit_i比new_i先到Np的情况,所以我们在代码中设置跳出循环的条件是new_i > Np
fitvalue = fit ./ sum(fit); % 被选中的概率,适应度越高的概率越大,累加为1
fitvalue = cumsum(fitvalue); % 累计概率。第i个元素,是原第1到i个元素之和
bet = sort(rand(Np,1)); % 随机生成Np个(种群个体数)0到1的数并排序
fit_i = 1;
new_i = 1;
while new_i <= Np
% 排名第fit_i的个体,相应的累积概率大于轮盘中第new_i大的随机数时被选中
if (fitvalue(fit_i)) > (bet(new_i))
%fprintf("选中第%d个个体,",fit_i)
choosef(new_i,:) = population(fit_i,:); % 该个体选中,赋值给choosef
new_i = new_i + 1;
%fprintf("轮盘随机数变为%d;",new_i)
else
%fprintf("第%d个个体未被选中,",fit_i)
fit_i = fit_i + 1;
%fprintf("准备查看第%d个个体",fit_i)
end
end
四、基因交叉
对被选中的个体进行基因交叉,被交叉位置的基因由我们的随机数来决定
% 交叉操作:第i个个体和第i+1个个体,进行第j位的基因互换
for i = 1:2:Np % 第1个和第2个个体,第3和第4个个体……两两交叉
p = rand; % 随机生成一个0到1之间的数,满足均匀分布
if p < Pc % 交叉概率Pc=0.85,及有85%的概率满足if语句
q = randi([0,1],1,N); % 生成1行N列的矩阵,其中元素随机是0或1
for j = 1:N % 对于12个物品基因(0或1),随机选中某些基因来进行交叉
if q(j) == 1 % 随机生成的q中该位置元素为1,意味着第j个物品基因被选中进行交叉
temp = choosef(i + 1,j); % 第i+1个个体的第j个基因赋值给临时变量
choosef(i + 1,j) = choosef(i,j); % 第i个个体的第j个基因赋值给第i+1个个体
choosef(i,j) = temp; % 同样,第i+1个个体的第j个基因复制给第i个个体,完成交叉
end
end
end
end
五、变异操作
for n = 1:Np % 每个个体
for m = 1:N % 每个基因
variation = rand(1,1); % 生成一个大于0小于1的随机数
if variation < Pv % Pv=0.02,则有2%的概率满足if
choosef(n,m) = ~choosef(n,m); % 符号"~"是取反,0变1,1变0
end
end
end
population = choosef; % 交叉和变异后的群体
population(1,:) = fBest; % 把交叉变异前的最优个体保留在群体首位
trace(t) = maxfit; % 本轮迭代的最优适应度
end
六、输出结果
fBest; % 迭代之后的最优个体
figure
plot(trace)
xlabel('迭代次数')
ylabel('目标函数值')
title('遗传算法适应度迭代')