余晖落尽暮晚霞,黄昏迟暮远山寻
本站
当前位置:网站首页 > 编程知识 > 正文

遗传算法简述

xiyangw 2023-09-17 16:20 9 浏览 0 评论

遗传算法也成进化算法,该算法受到达尔文进化论的启发提出的一种启发式搜索算法。

进化论

种群

生物的进化以群体的形式进行,这样的一个群体称为种群。

个体

组成种群的单个生物。

基因

一个遗传因子。

染色体

包含一组的基因。

生存竞争,适者生存

对环境适应度高的个体参与繁殖的机会比较多,后代就会越来越多。适应度低的个体参与繁殖的机会比较少,后代就会越来越少。

遗传与变异

新个体会遗传父母双方各一部分的基因,同时有一定的概率发生基因变异。

综述

繁殖过程,会发生基因交叉,基因突变 ,适应度低的个体会被逐步淘汰,而适应度高的个体会越来越多。那么经过N代的自然选择后,保存下来的个体都是适应度很高的,其中很可能包含史上产生的适应度最高的那个个体。

遗传算法

遗传算法将要解决的问题模拟成一个生物进化的过程,通过复制、交叉、突变等操作产生下一代的解,并逐步淘汰掉适应度函数值低的解,增加适应度函数值高的解。这样进化N代后就很有可能会进化出适应度函数值很高的个体。下面以0-1背包问题来讲解下遗传算法的步骤

  • 编码
  • 需要将问题的解编码成字符串的形式才能使用遗传算法。最简单的一种编码方式是二进制编码,即将问题的解编码成二进制位数组的形式。例如,问题的解是整数,那么可以将其编码成二进制位数组的形式。将0-1字符串作为0-1背包问题的解就属于二进制编码。

  • 选择
  • 选择一些染色体来产生下一代。一种常用的选择策略是比例选择。也就是轮盘赌算法,如下图所示


    群体中每一染色体指定饼图中一个小块。块的大小与染色体的适应性分数成比例,适应性分数愈高,它在饼图中对应的小块所占面积也愈大。为了选取一个染色体,要做的就是旋转这个轮子,直到轮盘停止时,看指针停止在哪一块上,就选中与它对应的那个染色体。


    若产生随机数为0.81,则6号个体被选中。

    // 轮盘赌代码示意
    /*
    * 按设定的概率,随机选中一个个体
    * P[i]表示第i个个体被选中的概率
    */
    int RWS()
    {
        m =0;
        r =Random(0,1); //r为0至1的随机数
        for(i=1;i<=N; i++)
        {
            /* 产生的随机数在m~m+P[i]间则认为选中了i
             * 因此i被选中的概率是P[i]
             */
            m = m + P[i];
            if(r<=m) return i;
        }
    }
    
  • 交叉
  • 2条染色体交换部分基因,来构造下一代的2条新的染色体。父辈染色体00000|011100000000|1000011100|000001111110|00101随机交叉遗传00000|000001111110|1000011100|011100000000|00101

  • 变异
  • 新产生的染色体中的基因会以一定的概率出错,称为变异。变异前: 000001110000000010000变异后: 000001110000100010000我们认为染色体交叉的概率为Pc,染色体变异的概率为Pm。适应度函数:用于评价某个染色体的适应度,用f(x)表示。有时需要区分染色体的适应度函数与问题的目标函数。例如:0-1背包问题的目标函数是所取得物品价值,但将物品价值作为染色体的适应度函数可能并不一定适合。适应度函数与目标函数是正相关的,可对目标函数作一些变形来得到适应度函数。

    遗传算法核心表示

    /**
     * 交叉遗传的概率Pc
     * 遗传变异的概率Pm
     * 种群规模M
     * 终止进化代数G
     * 当产生出一个个体的适应度超过给定Tf,则终止进化
     */
     步骤1
     初始化产生 Pc Pm M G Tf参数并随机生成第一代种群population,简称P1
     初始化P = P1
     do {
     	计算P中每一个个体的适应度F(i)
     	初始化空种群newP
     	do {
     		根据适应度比例选择算法选择出2个个体
     		if (rnd1 < Pc) {
     			进行交叉操作
     		}
     		if (rnd2 < Pm) { 进行变异操作 } 将两个操作后的个体放进newP中,即产生的新个体进入新的种群 } until (M个个体被创建) P = newP } until(任何染色体满足适应度或者繁殖代数>G)
    

    在这里我们看到了,这个随机选择以及产生后代的方式需要斟酌,如果设定的不好,那么很有可能这个种族最后就灭绝了,算个说话也就是我们没有得到我们的解。大自然这里还有一个规律叫做:物竞天择 适者生存在我们这里也需要对算法进行优化:择优 为了防止进化过程中产生的最优解被交叉和变异所破坏,可以将每一代中的最优解原封不动的复制到下一代中。

    具体实例


  • 理解实例
  • 求 f(x1, x2) = x1^3 + x2^2 + (x1 * (x1 – x2))的最大值,其中x1属于{-5, -3, 1, 3, 5}, x2属于{0, 2, 4}当然这个题目解法很多,穷举方法也非常的迅速。这个例子为了更加透彻的理解遗传算法。步骤1 编码我们此处定义隐射关系为[[0] = -5,[1] = -3,[2] = 0,[3] = 1,[4] = 2,[5] = 3,[6] = 4,[7] = 5]8可以用4位二进制表示,而x1和x2则用8位二进制即可完成验证比如{0110|0110}则表示[x1 = 3, x2 = 4]步骤2 生成种群,注意生成种群的数量以及作用域关系,写一段js代码来进行测试

    生成个体

    步骤3 随机选择父代进行通过交叉和变异生成子代(选出适应度较高的进行)

    产生多代并得到最后结果

    150

    代码示意,因为没有变异以及编码是否可以有更好的办法,所以只为显示整体过程

    console.log("遗传算法");
    var everyone = [];
    var number = 200;
    function in_array(search, array){
        for(var i in array){
            if(array[i]==search){
                return true;
            }
        }
        return false;
    }
    var genChromosome = function(scope) {
        var timestamp = new Date().getTime();
        var index = Math.ceil(Math.random() * timestamp) % scope.length;
        var chromosome = scope[index].toString(2);
        while (chromosome.length < 4) {
            chromosome = "0" + chromosome;
        }
        return chromosome;
    }
    
    // 计算每个的适应度
    var calFitness = function(omo) {
        var codes = [-5, -3, 0, 1, 2, 3, 4, 5];
        var arr1 = [-5, -3, 1, 3, 5];
        var arr2 = [0, 2, 4];
        var x1 = codes[parseInt(omo.substr(0, 4), 2)];
        var x2 = codes[parseInt(omo.substr(4, 4), 2)];
        if (x1 != undefined && x2 != undefined && in_array(x1, arr1) && in_array(x2, arr2)) {
            return x1 * x1 * x1 + x2 * x2 + (x1 * (x1 - x2));
        }
        return -9999;
    }
    
    function sortNumber(a,b) 
    { 
        return a - b 
    } 
    
    $('#genUnit').click(function() {
        $('#geti').html('');
        var scope1 = [0, 1, 3, 5, 7];
        var scope2 = [2, 4, 6];
        // 生成50组个体
        everyone = [];
        for (var i = 0; i < number; i++) {
            var new_omo = genChromosome(scope1) + genChromosome(scope2);
            everyone.push (new_omo);
        }
        for (var i = 0; i < everyone.length; i++) {
            $('#geti').append(everyone[i] + " ");
            if ((i + 1) % 10 == 0) {
                $('#geti').append("
    ");
            }
        }
    });
    
    // 交叉函数
    var cross = function(omo1, omo2) {
        // 针对这个,四位是一个染色体特征控制
        var ret = "";
        var timestamp = new Date().getTime();
        var rnd = Math.ceil(Math.random() * timestamp) % 4;
        if (rnd <= 1) {
            // 互换前四位
            for (var i = 0; i < 4; i++) {
                var tmp = omo1[i];
                omo1[i] = omo2[i];
                omo2[i] = tmp;
            }
        } else if (rnd <= 3) {
            // 互换后四位
            for (var i = 4; i < 8; i++) {
                var tmp = omo1[i];
                omo1[i] = omo2[i];
                omo2[i] = tmp;
            }
        }
        var rnd_next = Math.ceil(Math.random() * timestamp) % 2;
        if (rnd_next == 0) {
            ret = omo1;
        } else {
            ret = omo2;
        }
        return ret;
    }
    // 变异函数
    var variation = function(omo1, omo2) {
        // 变异某一位,然后做交叉运算
        // 这里暂时不需要,所以直接进行选择
        var timestamp = new Date().getTime();
        var rnd_next = Math.ceil(Math.random() * timestamp) % 2;
        if (rnd_next == 0) {
            ret = omo1;
        } else {
            ret = omo2;
        }
        return ret;
    }
    // 判断结束
    var finish = function() {
        // 这里直接看第五十代
    }
    
    $('#genNextUnit').click(function() {
        if (everyone.length == 0) {
            return
        }
        // 至少5代且满足best适应值占75%或最多50代
        var g_num = 0;
        while (g_num < 50) {
            // 假设淘汰20%,最优的保留,剩下随机
            var fitness_score = [];
            for (var i = 0; i < everyone.length; i++) {
                fitness_score.push(parseInt(calFitness(everyone[i])));
            }
            fitness_score.sort(sortNumber);
            var over = Math.ceil(fitness_score.length * 0.2)
            for (var i = 0; i < over; i++) {
                fitness_score.shift();
            }
            var best = fitness_score[fitness_score.length - 1];
            // 生成子代
            var new_generation = [];
            while (new_generation.length < number) {
                var curr_unit;
                // 选择
                var timestamp = new Date().getTime();
                var choose_fitness1 = everyone[Math.ceil(Math.random() * timestamp) % everyone.length];
                var choose_fitness2 = everyone[Math.ceil(Math.random() * timestamp) % everyone.length];
                if (calFitness(choose_fitness1) == best && calFitness(choose_fitness2) == best) {
                    // 进行交叉
                    curr_unit = cross(choose_fitness1, choose_fitness2)
                    if (Math.ceil(Math.random() * timestamp) % 100 < 2) {
                        // 进行变异
                        curr_unit = variation(choose_fitness1, choose_fitness2)
                    }
                } else if (Math.ceil(Math.random() * timestamp) % 100 > 50) {
                    // 进行交叉
                    curr_unit = cross(choose_fitness1, choose_fitness2)
                    // 进行变异
                    if (Math.ceil(Math.random() * timestamp) % 100 < 2) {
                        // 进行变异
                        curr_unit = variation(choose_fitness1, choose_fitness2)
                    }
                }
                if (curr_unit != undefined) {
                    if (calFitness(curr_unit) > -9999) {
                        new_generation.push(curr_unit);
                    }
                }
            }
            everyone = new_generation;
            g_num = g_num + 1;
        }
        var fitness_score = [];
        for (var i = 0; i < everyone.length; i++) {
            fitness_score.push(parseInt(calFitness(everyone[i])));
        }
        console.log(everyone[0]);
        fitness_score.sort(sortNumber);
        var best_number = fitness_score[fitness_score.length - 1];
        $('#zidai').html(best_number);
        // 01110010
    });

    相关推荐

    数控系统常见术语详解,机加工人士必备资料
    数控系统常见术语详解,机加工人士必备资料

    增量编码器(Incrementpulsecoder)回转式位置测量元件,装于电动机轴或滚珠丝杠上,回转时发出等间隔脉冲表示位移量。由于没有记忆元件,故不能准...

    2023-09-24 17:42 xiyangw

    功、功率、扭矩的关系

    功=功率×时间work=power×timeW=P×T功=力×距离work=force×lengthW=F×LP×T=F×LP=F×L/T=F×V(velocity)具体到电机输出轴上,圆...

    Wi-Fi协议(802.11 )常见专业术语汇总
    Wi-Fi协议(802.11 )常见专业术语汇总

    Wi-Fi协议(802.11)常见专业术语汇总AP(Accesspoint的简称,即访问点,接入点):是一个无线网络中的特殊节点,通过这个节点,无线网络中的...

    2023-09-24 17:41 xiyangw

    不需要策略模式也能避免满屏if/else
    不需要策略模式也能避免满屏if/else

    满屏if/elsejava复制代码publicstaticvoidmain(String[]args){inta=1;if...

    2023-09-24 17:41 xiyangw

    喜极而泣,我终于干掉了该死的 if-else
    喜极而泣,我终于干掉了该死的 if-else

    推荐阅读:面试淘宝被Tomcat面到“自闭”,学习这份文档之后“吊打”面试官刷完spring+redis+负载均衡+netty+kafka面试题,再去面试BAT...

    2023-09-24 17:40 xiyangw

    Python中使用三元运算符简化if-else语句
    Python中使用三元运算符简化if-else语句

    Python是一种极简主义的编程语言,相比其他编程语言,在多个地方简化了代码的写法,可以让我们用更少的时间更简洁地完成工作。以赋值运算符为例:a=a+b简化...

    2023-09-24 17:40 xiyangw

    雅思课堂 | 雅思口语写作句型第二讲
    雅思课堂 | 雅思口语写作句型第二讲

    纯干货,无废话用最少的时间学最制胜的内容!泡图书馆泡不过学霸?碎片时间也能弯道超车!向着雅思8分行动起来吧!雅思口语写作句型1.Ipreferseeing...

    2023-09-24 17:39 xiyangw

    设计模式(三)——简单的状态模式代替if-else
    设计模式(三)——简单的状态模式代替if-else

    博主将会针对Java面试题写一组文章,包括J2ee,SQL,主流Web框架,中间件等面试过程中面试官经常问的问题,欢迎大家关注。一起学习,一起成长。前言大多数开...

    2023-09-24 17:38 xiyangw

    如何优化代码中大量的if/else,switch/case?

    前言随着项目的迭代,代码中存在的分支判断可能会越来越多,当里面涉及到的逻辑比较复杂或者分支数量实在是多的难以维护的时候,我们就要考虑下,有办法能让这些代码变得更优雅吗?正文使用枚举这里我们简单的定义一...

    优秀程序员早就学会用“状态模式”代替if-else了
    优秀程序员早就学会用“状态模式”代替if-else了

    2020年已经进入倒计时了,大家立好的flag完成了吗?2020实“鼠”不易,希望2021可以“牛”转乾坤。简介状态模式是行为型设计模式的一种。其设计理念是当对...

    2023-09-24 17:37 xiyangw

    用Select Case语句对执行多条件进行控制
    用Select Case语句对执行多条件进行控制

    今日的内容是"VBA之EXCEL应用"的第六章"条件判断语句(If...Then...Else)在VBA中的利用"。这讲是第三节...

    2023-09-24 17:37 xiyangw

    c#入门教程(四)条件判断if else

    条件判断,是编程里常用的判断语句,比如某个代码如果满足条件就执行a代码块否则就执行b代码块。案例1:inti=2*5;if(a>0){执行a代码块}elseif(a<0){执行b代码块...

    每日学编程之JAVA(十一)—条件语句(if……else)

    一个if语句包含一个布尔表达式和一条或多条语句。如果布尔表达式的值为true,则执行if语句中的代码块,否则执行if语句块后面的代码。if语句后面可以跟else语句,当if语句...

    不需要策略模式也能避免满屏if/else

    除了使用策略模式以外,还可以使用其他设计模式来避免满屏if/else的问题。以下是一些可能的解决方案:工厂模式:将if/else语句移到工厂类中,由工厂类负责创建对象。这样可以将if/else语句从客...

    围绕ifelse与业务逻辑的那些梗
    围绕ifelse与业务逻辑的那些梗

    ifelse很重要,几乎是程序员编程核心,业务逻辑与规则也通过ifelse体现出来,语句简单但是背后文章很大,先看几则幽默图:1.也许默认使用returnf...

    2023-09-24 17:36 xiyangw

    取消回复欢迎 发表评论: