遗传算法求解函数极大值问题(附测试代码)

遗传算法(Genetic Algorithm, GA)是模拟达尔文生物进化论的自然选择和遗传学机理的生物进化过程的计算模型,是一种通过模拟自然进化过程搜索最优解的方法。
简而言之,遗传算法就是通过每次选择比较好的个体进入下一次循环来保证每一轮解的最优特性,其核心思想有以下几个方面。
(1)初始化值(染色体),转化成二进制的形式(为了方便交叉和变异)
(2)使用轮盘赌算法设计策略来选择下一轮进入循环的染色体(只要是为了防止当前适应度值不太好的染色体直接被淘汰)
(3)复制染色体(保证每一轮染色体的条数和初始染色体条数一样,比如初始染色体有4条,通过轮盘赌算法后只选择了3条,那么剩下的一条一般是复制当前轮中比较好的染色体,当然,这个时候4条染色体中有2条是一样的,所以要进行交叉和变异)
(4)交叉,交叉的策略很多,可以选择任意两条染色体相交叉(其实就是交换染色体对应的二进制的某些值,比如选择第一条染色体对应的二进制前3个值和第二条染色体对应的二进制前3个值对换,交叉的目的在于检验这些比较好的染色体相互组合后是否能达到求解要求,也可以说是保留最优染色体基因,其实交叉后也有可能会变差)
(5)变异,当染色体相互交叉后并不能找到最优值,就需要变异,变异就是改变某条染色体中对应的基因值,把染色体对应的二进制中某个1变成0,或者0变成1,变异策略也有很多,需要几个基因变异因问题不同而不同。
交叉和变异都是为了防止进入局部最优。
为了方便说明,根据遗传算法原理,求解二次函数极大值问题,定义域为(1,10)
在这里插入图片描述
步骤为:
(1)根据定义域,初始化染色体数目和值
(2)计算每条染色体对应的y值
(3)根据轮盘赌算法选择下一次要遗传的染色体,染色体数目不够就复制
(4)二进制编码染色体
(5)交叉
(6)变异,更新下一轮循环染色体
(7)没有达到最大循环次数,返回(2),否则,输入目标值。
另外,交叉和变异后最好都检验下新的染色体是否还在定义域范围,如果超出范围,要调整。
代码如下:

clc;
clear all;
%遗传算法求y=x1^2在区间[1 10]的最大值,求y的值和x的值
%初始种群规模M=4
%终止迭代次数
%交叉概率
%变异概率
% 复制 、交叉、变异
beginNum=1+(10-1)*rand(1,4)%随机生成4个初始值,染色体
%计算初始使用度值
T=100;%最大循环次数
tt=1;
maxsyd=[];
while tt<=T
    beginNum
    zydz=[];
    for j=1:length(beginNum)
        zydz(j)=beginNum(j)^2;
    end
    
%      if max(zydz)==100
%          beginNum;
%          break;
%      end
    
    %根据轮盘赌算法决定下次遗传的
    %计算适应度的选择概率
    p=[];
    for z=1:length(zydz)
        p(z)=zydz(z)/sum(zydz);
    end
    p;
    %计算累加概率q
    q=[];
    q(1)=p(1);
    for y=2:length(p)
        q(y)=p(y)+ q(y-1);
    end
    q;
    gxnum=[];
    r=rand(1,length(beginNum));%在[0 1]之间产生随机数字r产生length(beginNum)个
    for k=1:length(r)
        if r(k)<=q(1)
            gxnum=[gxnum beginNum(1)];
        end
        for kk=2:length(q) %每个随机数字r在q中的范围
            if q(kk-1)<r(k)&&r(k)<=q(kk)
                gxnum=[gxnum beginNum(kk)];
            end
        end
    end
    gxnum=unique(gxnum,'stable');
    %判断是否需要复制
    if length(gxnum)<length(beginNum)
        % 选择复制优势染色体
        while length(gxnum)~=length(beginNum)
            gxnum=[gxnum max(beginNum)];
        end
    end
    
    m=8;
    newbeginenum={};%转换成二进制后的初始数,方便变异和交叉操作
    for i=1:length(gxnum)
        n=beginNum(i);
        a=dec2bin(n*2^m);
        %     b=[a(1:end-m),'.',a(end-m+1:end)];
        % str2double(a)
        newbeginenum{i}=a;
    end
    t=char(newbeginenum(1));%转成字符串类型
    %所有二进制的位数必须一样,不足的在前面补0
    yycount=0;
    for yy=1:length(newbeginenum)
        % 找最长位数的二进制
        yyt1=length(char(newbeginenum(yy)));
        if yyt1>yycount
            yycount=yyt1;
        end
    end
    for pj=1:length(newbeginenum)
        yy2=length(char(newbeginenum(pj)));
        if yy2<yycount
            tempj(1:yycount-yy2)='0';
            newbeginenum{pj}=strcat(tempj,char(newbeginenum(pj)));%更新newbeginenum
        end
    end
    
    nm=2;%交换前2位
    jcnewbeginenum={};%交叉产生新的染色体jcnewbeginenum
    for nk=1:2:length(newbeginenum)-1
        t1=char(newbeginenum(nk));
        t2=char(newbeginenum(nk+1));
        tz1=t1(1:nm);
        tz2=t2(1:nm);
        % 交换
        tztemp=tz1;
        t1(1:nm)=tz2;
        t2(1:nm)=tztemp;
        jcnewbeginenum{nk}=t1;
        jcnewbeginenum{nk+1}=t2;
    end
    %判断变异是否超出定义域范围
    
    jcnewbeginenum(3);%
    % 变异,根据要求,设置变异概率10%,
    %变异基因个数jycount
    byhbegine={}; %变异后的值,等下记得判断是否超出定义域的范围
    for jyk=1:length(jcnewbeginenum)
        jycount=ceil(length(char(jcnewbeginenum(jyk)))*0.1);
        % rk=randperm(length(char(jcnewbeginenumjyk))),jycount));%产生变异基因的位置
        rk=randperm(length(char(jcnewbeginenum(jyk))),jycount);
        % 替换变异位置
        bywz=char(jcnewbeginenum(jyk));
        for byw=1:length(rk)
            if strcmp(bywz(rk(byw)),'0')
                bywz(rk(byw))='1';
            else
                bywz(rk(byw))='1';
                
            end
            %     bywz(rk(byw))=~bywz(rk(byw));
        end
        byhbegine{jyk}=bywz;
    end
    %把变异后的值转换成十进制替换初始值
    zzbyhbegine=[];
    for ncs=1:length(byhbegine)
        tempaa=char(byhbegine(ncs));
        %二进制转换成十进制
        zzbyhbegine(ncs)=bin2dec(tempaa(1:end-m))+bin2dec(tempaa(end-m+1:end))/2^m;
    end
    beginNum=zzbyhbegine;
    for bj=1:length(beginNum)
        if beginNum(bj)<1
            beginNum(bj)=1;
        end
        if beginNum(bj)>10
            beginNum(bj)=10;
        end
    end
     tt=tt+1;
     maxsyd=[maxsyd max(zydz)];
end
xsyd=1:100;
plot(xsyd,maxsyd,'r-')

运行结果
在这里插入图片描述
可以看到,在定义域为(1,10)中,遗传算法收敛速度还是非常快的(大约在第三轮就已经收敛了)。另外,在实验过程中,由于变异和交叉策略选择的原因,发现该算法还是会陷入局部最优,其陷入局部最优的概率为约为5%。

好的,以下是可以参考的MATLAB代码: ``` % 导入数据并归一化处理 load data.mat data = normalize(data); % 划分训练集和测试集 train_ratio = 0.8; [train_data, test_data] = split_data(data, train_ratio); % 进行支持向量机的训练和预测 C_range = 2.^(-5:2:15); gamma_range = 2.^(-15:2:3); [CC, gamma] = meshgrid(C_range, gamma_range); params = [CC(:), gamma(:)]; num_params = size(params, 1); svm_acc = zeros(num_params, 1); for i = 1:num_params svm_model = svmtrain(train_data(:,end), train_data(:,1:end-1), ... sprintf('-c %f -g %f -q', params(i,1), params(i,2))); [~, svm_acc(i)] = svmpredict(test_data(:,end), test_data(:,1:end-1), svm_model); end % 用遗传算法进行结构参数寻优 nvars = 2; % 参数个数 lb = [2^(-5), 2^(-15)]; % 参数下界 ub = [2^15, 2^3]; % 参数上界 options = gaoptimset('PopulationSize', 50, 'Generations', 100, 'StallGenLimit', 50); [x, fval] = ga(@(params) fitness(params, svm_model, train_data), nvars, [], [], [], [], lb, ub, [], options); % 输出最佳参数和目标值 fprintf('最佳参数:C=%f, gamma=%f\n', x(1), x(2)); fprintf('目标值:%.4f\n', -fval); % 定义适应度函数 function acc = fitness(params, svm_model, train_data) C = params(1); gamma = params(2); svm_model = svmtrain(train_data(:,end), train_data(:,1:end-1), ... sprintf('-c %f -g %f -q', C, gamma)); [~, acc] = svmpredict(train_data(:,end), train_data(:,1:end-1), svm_model); acc = -acc(1); end % 定义数据归一化函数 function [norm_data] = normalize(data) norm_data = (data - min(data)) ./ (max(data) - min(data)); end % 定义数据集划分函数 function [train_data, test_data] = split_data(data, train_ratio) num_train = round(size(data, 1) * train_ratio); rand_indices = randperm(size(data, 1)); train_data = data(rand_indices(1:num_train), :); test_data = data(rand_indices(num_train+1:end), :); end ``` 其中,`data`是导入的数据,最后一列为标签,其余列为特征。`split_data`函数用于将数据划分为训练集和测试集。`normalize`函数用于归一化处理数据。在支持向量机部分,使用`meshgrid`函数生成所有可能的参数组合,然后用`svmtrain`和`svmpredict`函数进行训练和预测,并计算测试集上的准确率。在遗传算法部分,使用`ga`函数进行参数寻优,其中适应度函数`fitness`的输入为参数向量,输出为训练集上的准确率的相反数(因为`ga`函数默认寻找最小值,而我们希望最大化准确率)。最后输出最佳参数和目标值(即最佳准确率的相反数)。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值