经典算法(9)、遗传算法(1):遗传算法简介及基本遗传算法

来源:互联网 发布:diy耳放 淘宝 靠谱么 编辑:程序博客网 时间:2024/05/19 06:35

遗传算法简介


据说,可以用在很多领域。

先学习在函数优化方面的应用。

据说,对于非线性、多模型、多目标的函数优化问题,GA似乎可以得出不错的结果。

“优胜劣汰”。

基本操作:选择、交叉,变异。

每一个基本操作,又有很多种方法。


1. 选择。

根据适应度来选择。在函数优化问题中,为了找最大值,那适应度可以直接定义为f(x0),把某一个个体送入函数,该函数的输出结果。、

(1) 按比例的适应度计算

(2) 基于排序的适应度计算

选择一般有:

(1) 轮盘赌(目前我只知道这个。就像外面搞抽奖活动,一个盘,一根指针。你去转那个盘,最后指针会停在某个扇形上。不过一般都是谢谢惠顾。)

(2) 随机遍历抽样

(3) 局部选择

(4) 截断选择

(5) 锦标赛选择


2. 交叉。

结合父辈的信息,交配产生信的个体。根据个体编码方式不同,可以有:

(1) 实值重组

离散重组

中间重组

线性重组

扩展线性重组

(2) 二进制交叉

单点交叉(我只知道,

多点交叉 这两种)

均匀交叉

洗牌交叉

缩小代理交叉


3. 变异

对子代基因按小概率进行扰动。根据个体编码方式不同,可以有:

(1) 实值变异

(2) 二进制变异(如:对某个个体的二进制编码的某一位取反)


基本遗传算法


用基本遗传算法求一元数量值函数的(近似)最大值。




几个关键点。
1. 个体的初始化是,在区间 [a,b] 上,随机挑一个数。这个随机数可以这样生成。 a + [b - a] / L * n, n是随机的。类似于对连续函数的量化过程(毕竟我是学通信的)。
2. 因为函数比较简单,又是求最大值,所以适应度可以直接把个体往目标函数 f( ) 里面代,返回值就是适应度。
3. 轮盘赌的代码实现可以这样实现。把每一个个体的适应度排在一条直线上,累加起来。(最好把适应度都归到这个区间。不然用轮盘赌的话,一个负数怎么能称为概率?)随机生成[0,1]的数,看落在哪个个体身上,就选它作为以第一代的父亲。为了简单,母亲就任意了(这婚姻也太随意了……)。
4. 如果要求函数f(x)的最小值的话,可以求去找 -f(x) 的最大值。目标函数写成 - f(x) 就好了。

这里贴上书上的代码。上面本来有一些注释,我又加了一点。

Main
clear;close all;clc%%NP = 100;NG = 100;precision = 0.001;prob_cross = 0.9;prob_variation = 0.01;x_low = 0;x_high = 40;[xv,fv] = my_GA1(@fitness,x_low,x_high,NP,NG,prob_cross,prob_variation,precision);[xv,fv]x = x_low:0.01:x_high;for i = 1:length(x)    y(i) = fitness(x(i));endplot(x,y)
Main函数里面,调用my_GA1的时候,第一个参数传的是@fitness。fitness是一个函数,@fitness是函数句柄。感觉可以理解为函数指针。
适应度函数(简单起见可以直接选用目标函数)
function [ res ] = fitness( x )% function [ res ] = fitness( x )% 这里直接把目标函数当做适应度% 要找f(x) 在区间 [a,b] 上的最大值res = (x^3 - 60 * x^2 + 900 * x + 100);% res =  (x - 1) * (x - 2)^2;% res = sin(2*pi*x);% res = -(x^2-20);end
基本遗传算法
function [xv,fv]=my_GA1(fitness,a,b,NP,NG,Pc,Pm,eps)L = ceil(log2((b-a)/eps+1));  %根据离散精度,确定二进制编码需要的码长x = zeros(NP,L); % NP个个体,L是二进制编码的长度 % NP行,L列。每个个体用L位二进制代表其基因。for i=1:NP        x(i,:) = Initial(L);   %种群初始化 % x随便取-_-!        %     fx 各个个体往目标函数里面代,返回值    fx(i) = fitness(Dec(a,b,x(i,:),L));  %个体适应值 --> 可以把个体往目标函数里面代 -_-!    endfx = fx - min(fx);  %%%%%%%%%%%%%%% 调整为全是正数!for k=1:NG % 一共产生NG代        sumfx = sum(fx);                %所有个体适应值之和        Px = fx/sumfx;                   %所有个体适应值的平均值 --> 不是平均值啊,是各个个体适应度的比例,个体的选择概率        PPx = 0;        PPx(1) = Px(1);                 % 这是累计概率        for i=2:NP                        %用于轮盘赌策略的概率累加                PPx(i) = PPx(i-1) + Px(i);            end        for i=1:NP % 轮转NP次,相当于是生了N个孩子                theta = rand(); % 每次轮转,就产生一个(0,1)的数,看落在哪个范围                for n=1:NP                        if theta <= PPx(n)  % 累计范围 --> 这种写法相当于是NP个if… -_-!                                SelFather = n;      %根据轮盘赌策略确定的父亲                                break;                            end                    end                Selmother = floor(rand()*(NP-1))+1;  %随机选择母亲(这段婚姻真随意,甚至会出现“自交”???自己和自己交配。。。?)                posCut = floor(rand()*(L-2)) + 1;     %随机确定交叉点                r1 = rand();                               if r1<=Pc      % 以一定的概率,发生交叉           %交叉                        nx(i,1:posCut) = x(SelFather,1:posCut);  % 这种交叉的方法是,用父亲的前posCut & 母亲的后 posCut 相结合                        nx(i,(posCut+1):L) = x(Selmother,(posCut+1):L);                        r2 = rand();                        if r2 <= Pm         % 以一定的概率,发生变异             %变异                                posMut = round(rand()*(L-1) + 1); % 变异的位置 这里是 1位                                nx(i,posMut) = ~nx(i,posMut); % 这里的变异就是,某一位取反                            end                    else                        nx(i,:) = x(SelFather,:); % 如果不交叉,子代染色体就是父代                    end            end        x = nx; % 新的个体,重新赋值给了x        for i=1:NP                fx(i) = fitness(Dec(a,b,x(i,:),L));   %子代适应值            end        fx = fx - min(fx);  %%%%%%%%%%%%%%% 调整为全是正数!    end% 最后,在最终一代里面选,最佳适应的那个个体fv = -inf;for i=1:NP        fitx = fitness(Dec(a,b,x(i,:),L));        if fitx > fv                fv = fitx;                                %取个体中的最好值作为最终结果                xv = Dec(a,b,x(i,:),L);            end    endfunction result = Initial(len)         %初始化函数for i=1:len        r = rand();        % X = rand returns a single uniformly     % distributed random number     % in the interval (0,1).        result(i) = round(r);       endfunction y = Dec(a,b,x,L)         %二进制编码转换为十进制编码base = 2.^((L-1):-1:0);y = dot(base,x);y = a + y*(b-a)/(2^L-1);

近似最大值点是 x = 10.0038,近似最大值是 fv = 4.1000e+03


为了求最小值,把适应度函数前面填个负号。
res = - (x^3 - 60 * x^2 + 900 * x + 100);
然后,输出结果的时候,[xv,-fv] 就代表最小值点和最小值了。
29.9992  100.0000

有个问题,这是一种概率的办法,所以就算参数相同,每次出来的结果也可能不一样 -_-!!
当然,基本算法肯定很简单,只是为了入门学习一下。以后再慢慢改善、完善。



说明
生成的每一代的每一个个体,都按一定的概率发生交叉和变异。
如果没有交叉,那下一代就先用父亲的基因,再去考虑是否要变异。





0 0
原创粉丝点击