遺傳算法簡述

遺傳算法也成進化算法,該算法受到達爾文進化論的啟發提出的一種啟發式搜索算法。

進化論

種群

生物的進化以群體的形式進行,這樣的一個群體稱為種群。

個體

組成種群的單個生物。

基因

一個遺傳因子。

染色體

包含一組的基因。

生存競爭,適者生存

對環境適應度高的個體參與繁殖的機會比較多,後代就會越來越多。適應度低的個體參與繁殖的機會比較少,後代就會越來越少。

遺傳與變異

新個體會遺傳父母雙方各一部分的基因,同時有一定的概率發生基因變異。

綜述

繁殖過程,會發生基因交叉,基因突變 ,適應度低的個體會被逐步淘汰,而適應度高的個體會越來越多。那麼經過N代的自然選擇後,保存下來的個體都是適應度很高的,其中很可能包含史上產生的適應度最高的那個個體。

遺傳算法

遺傳算法將要解決的問題模擬成一個生物進化的過程,通過複製、交叉、突變等操作產生下一代的解,並逐步淘汰掉適應度函數值低的解,增加適應度函數值高的解。這樣進化N代後就很有可能會進化出適應度函數值很高的個體。下面以0-1揹包問題來講解下遺傳算法的步驟

  • 編碼
  • 需要將問題的解編碼成字符串的形式才能使用遺傳算法。最簡單的一種編碼方式是二進制編碼,即將問題的解編碼成二進制位數組的形式。例如,問題的解是整數,那麼可以將其編碼成二進制位數組的形式。將0-1字符串作為0-1揹包問題的解就屬於二進制編碼。

  • 選擇
  • 選擇一些染色體來產生下一代。一種常用的選擇策略是比例選擇。也就是輪盤賭算法,如下圖所示

    遺傳算法簡述


    群體中每一染色體指定餅圖中一個小塊。塊的大小與染色體的適應性分數成比例,適應性分數愈高,它在餅圖中對應的小塊所佔面積也愈大。為了選取一個染色體,要做的就是旋轉這個輪子,直到輪盤停止時,看指針停止在哪一塊上,就選中與它對應的那個染色體。

    遺傳算法簡述


    若產生隨機數為0.81,則6號個體被選中。

    <code>// 輪盤賭代碼示意
    /*
    * 按設定的概率,隨機選中一個個體
    * 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;
    }
    }
    /<code>
  • 交叉
  • 2條染色體交換部分基因,來構造下一代的2條新的染色體。父輩染色體00000|011100000000|1000011100|000001111110|00101隨機交叉遺傳00000|000001111110|1000011100|011100000000|00101

  • 變異
  • 新產生的染色體中的基因會以一定的概率出錯,稱為變異。變異前: 000001110000000010000變異後: 000001110000100010000我們認為染色體交叉的概率為Pc,染色體變異的概率為Pm。適應度函數:用於評價某個染色體的適應度,用f(x)表示。有時需要區分染色體的適應度函數與問題的目標函數。例如:0-1揹包問題的目標函數是所取得物品價值,但將物品價值作為染色體的適應度函數可能並不一定適合。適應度函數與目標函數是正相關的,可對目標函數作一些變形來得到適應度函數。

    遺傳算法核心表示

    <code>/**
    * 交叉遺傳的概率Pc
    * 遺傳變異的概率Pm
    * 種群規模M
    * 終止進化代數G
    * 當產生出一個個體的適應度超過給定Tf,則終止進化
    */
    步驟1
    初始化產生 Pc Pm M G Tf參數並隨機生成第一代種群population,簡稱P1
    初始化P = P1
    do {
    \t計算P中每一個個體的適應度F(i)
    \t初始化空種群newP
    \tdo {
    \t\t根據適應度比例選擇算法選擇出2個個體
    \t\tif (rnd1 < Pc) {
    \t\t\t進行交叉操作
    \t\t}
    \t\tif (rnd2 < Pm) { 進行變異操作 } 將兩個操作後的個體放進newP中,即產生的新個體進入新的種群 } until (M個個體被創建) P = newP } until(任何染色體滿足適應度或者繁殖代數>G)
    /<code>

    在這裡我們看到了,這個隨機選擇以及產生後代的方式需要斟酌,如果設定的不好,那麼很有可能這個種族最後就滅絕了,算個說話也就是我們沒有得到我們的解。大自然這裡還有一個規律叫做:物競天擇 適者生存在我們這裡也需要對算法進行優化:擇優 為了防止進化過程中產生的最優解被交叉和變異所破壞,可以將每一代中的最優解原封不動的複製到下一代中。

    具體實例


  • 理解實例
  • 求 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

    代碼示意,因為沒有變異以及編碼是否可以有更好的辦法,所以只為顯示整體過程

    <code>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
    });/<code>


    分享到:


    相關文章: