遺傳演算法組卷使用心得

weixin_33768481發表於2018-12-22

什麼是遺傳演算法?

遺傳演算法(Genetic Algorithm)是模擬達爾文生物進化論的自然選擇和遺傳學機理的生物進化過程的計算模型,是一種通過模擬自然進化過程搜尋最優解的方法。

我們都用它來做什麼?

一是基於遺傳演算法的機器學習,這一研究課題把遺傳演算法從歷來離散的搜尋空間的優化搜尋演算法擴充套件到具有獨特的規則生成功能的機器學習演算法。

二是遺傳演算法和神經網路、模糊推理以及混沌理論等其它智慧計算方法相互滲透和結合,這對開拓21世紀中新的智慧計算技術將具有重要的意義。

三是並行處理的遺傳演算法的研究十分活躍。這一研究不僅對遺傳演算法本身的發展,而且對於新一代智慧計算機體系結構的研究都是十分重要的。

四是遺傳演算法和另一個稱為人工生命的嶄新研究領域正不斷滲透。所謂人工生命即是用計算機模擬自然界豐富多彩的生命現象,其中生物的自適應、進化和免疫等現象是人工生命的重要研究物件,而遺傳演算法在這方面將會發揮一定的作用。

五是遺傳演算法和進化規劃(Evolution Programming,EP)以及進化策略(Evolution Strategy,ES)等進化計算理論日益結合。目前,這三者之間的比較研究和彼此結合的探討正形成熱點。

當然,本人才疏學淺,只會用其自動組個卷。

遺傳演算法基本運算過程

a) 初始化:設定進化代數計數器t=0,設定最大進化代數T,隨機生成M個個體作為初始群體P(0)。

b) 個體評價:計算群體P(t)中各個個體的適應度。

c) 選擇運算:將選擇運算元作用於群體。選擇的目的是把優化的個體直接遺傳到下一代或通過配對交叉產生新的個體再遺傳到下一代。選擇操作是建立在群體中個體的適應度評估基礎上的。

d) 交叉運算:將交叉運算元作用於群體。遺傳演算法中起核心作用的就是交叉運算元。

e) 變異運算:將變異運算元作用於群體。即是對群體中的個體串的某些基因座上的基因值做變動,群體P(t)經過選擇、交叉、變異運算之後得到下一代群體P(t+1)。

f) 終止條件判斷:若t=T,則以進化過程中所得到的具有最大適應度個體作為最優解輸出,終止計算。

例項分析

試題實體類:本試題實體針對大學英語四級設計,包含寫作、聽力、詞彙理解、長閱讀、仔細閱讀兩篇、翻譯7個大題。並且含有遺傳演算法相關屬性及方法。

package com.cet.pojo;  
  
import java.util.List;  
import java.util.Random;  
import com.cet.service.ObjectService;  
import com.cet.tool.Algorithm;  
  
/** 
 * Test entity. 
 */  
public class Test implements java.io.Serializable {  
  
    /** 
     * 試題 
     */  
    private static final long serialVersionUID = 1L;  
    // Fields  
    private Integer id;  
    private String name;  
    private BaseWriting baseWriting;  
    private BaseListening baseListening;  
    private BaseWordunderstand baseWordunderstand;  
    private BaseLongreading baseLongreading;  
    private BaseCarereading baseCarereading1;  
    private BaseCarereading baseCarereading2;  
    private BaseTranslate baseTranslate;  
    private int ismeta;  
  
    // 遺傳演算法相關屬性  
    private float difficulty = 0;// 試卷難度  
    private double Fitness = 0;// 試卷適應度  
  
    public int genes[] = new int[7];// 試卷基因序列  
  
    /** default constructor */  
    public Test() {}  
  
    // 遺傳演算法相關方法  
    /** 
     * 計算試卷個體難度係數 計算公式: 每題難度*分數求和除總分 
     *  
     * @return 
     */  
    public float getDifficulty() {  
        if (difficulty == 0) {  
            float _difficulty = (baseWriting.getDifficulty() * (float) 106.5  
                    + baseListening.getDifficulty() * (float) 248.5  
                    + baseTranslate.getDifficulty() * (float) 106.5  
                    + baseWordunderstand.getDifficulty() * (float) 36  
                    + baseLongreading.getDifficulty() * (float) 71  
                    + baseCarereading1.getDifficulty() * (float) 71 + baseCarereading2  
                    .getDifficulty()  
                    * (float) 71);  
            difficulty = (_difficulty / (float) 710.5);  
        }  
        return difficulty;  
    }  
  
    /** 
     * 計算個體適應度 公式為:f=1-|EP-P| 其中EP為期望難度係數,P為種群個體難度係數 
     *  
     * @param difficulty 
     *            期望難度係數 
     */  
    public double getFitness(double EP) {  
        if (Fitness == 0) {  
            Fitness = 1 - Math.abs(EP - getDifficulty());  
        }  
        return Fitness;  
    }  
  
    /** 
     * 功能:避免重複題型 
     * 檢查生成的Test的所有題型是否資料庫已經存在,只要Test裡有種題型和資料庫的某個Test一樣,就更換該題型為資料庫所有Test裡都沒有的。 
     *  
     * @param test 
     * @return 
     */  
      public boolean checkTest() {  
  
        ObjectService objectService = Algorithm.objectService;  
        Random random = new Random();  
  
        List<?> notInList = objectService.getObjectNotIn("BaseWriting");  
        if (notInList.size() < 1) {  
            return false;  
        }  
        baseWriting = (BaseWriting) notInList.get(random.nextInt(notInList  
                .size()));  
  
        notInList = objectService.getObjectNotIn("BaseListening");  
        if (notInList.size() < 1) {  
            return false;  
        }  
        baseListening = (BaseListening) notInList.get(random.nextInt(notInList  
                .size()));  
  
        notInList = objectService.getObjectNotIn("BaseWordunderstand");  
        if (notInList.size() < 1) {  
            return false;  
        }  
        baseWordunderstand = (BaseWordunderstand) notInList.get(random  
                .nextInt(notInList.size()));  
  
        notInList = objectService.getObjectNotIn("BaseLongreading");  
        if (notInList.size() < 1) {  
            return false;  
        }  
        baseLongreading = (BaseLongreading) notInList.get(random  
                .nextInt(notInList.size()));  
  
        notInList = objectService.getObjectNotIn("BaseCarereading");  
        if (notInList.size() < 2) {  
            return false;  
        }  
        int ran = random.nextInt(notInList.size());  
        baseCarereading1 = (BaseCarereading) notInList.get(ran);  
        notInList.remove(ran);  
        baseCarereading2 = (BaseCarereading) notInList.get(random  
                .nextInt(notInList.size()));  
  
        notInList = objectService.getObjectNotIn("BaseTranslate");  
        if (notInList.size() < 1) {  
            return false;  
        }  
        baseTranslate = (BaseTranslate) notInList.get(random.nextInt(notInList  
                .size()));  
  
        return true;  
    }  
  
    /** 
     * 功能:隨機生成一套試卷 
     *  
     * @return 
     */  
    public void getRandomTest() {  
  
        BaseWriting baseWriting = (BaseWriting) getRandomObject(  
                BaseWriting.class, "BaseWriting");  
        setBaseWriting(baseWriting);  
        genes[0] = baseWriting.getId();  
  
        BaseListening baseListening = (BaseListening) getRandomObject(  
                BaseListening.class, "BaseListening");  
        setBaseListening(baseListening);  
        genes[1] = baseListening.getId();  
  
        BaseWordunderstand baseWordunderstand = (BaseWordunderstand) getRandomObject(  
                BaseWordunderstand.class, "BaseWordunderstand");  
        setBaseWordunderstand(baseWordunderstand);  
        genes[2] = baseWordunderstand.getId();  
  
        BaseLongreading baseLongreading = (BaseLongreading) getRandomObject(  
                BaseLongreading.class, "BaseLongreading");  
        setBaseLongreading(baseLongreading);  
        genes[3] = baseLongreading.getId();  
  
        BaseCarereading baseCarereading1 = (BaseCarereading) getRandomObject(  
                BaseCarereading.class, "BaseCarereading");  
        setBaseCarereading1(baseCarereading1);  
        genes[4] = baseCarereading1.getId();  
  
        BaseCarereading baseCarereading2;  
        do {  
            baseCarereading2 = (BaseCarereading) getRandomObject(  
                    BaseCarereading.class, "BaseCarereading");  
        } while (baseCarereading2.getId() == baseCarereading1.getId());  
        setBaseCarereading2(baseCarereading2);  
        genes[5] = baseCarereading2.getId();  
  
        BaseTranslate baseTranslate = (BaseTranslate) getRandomObject(  
                BaseTranslate.class, "BaseTranslate");  
        setBaseTranslate(baseTranslate);  
        genes[6] = baseTranslate.getId();  
    }  
  
    /** 
     * 功能:隨機獲取一個題型物件 
     *  
     * @param clas 
     * @param table 
     * @return 
     */  
    public Object getRandomObject(Class<?> clas, String table) {  
        ObjectService objectService = Algorithm.objectService;  
        Random random = new Random();  
        Object obj = objectService.getObjectById(clas, random  
                .nextInt(objectService.getMaxID(table)) + 1);  
        return obj;  
    }  
  
    // Property accessors  
    public Integer getId() {  
        return this.id;  
    }  
  
    public void setId(Integer id) {  
        this.id = id;  
    }  
  
    public BaseLongreading getBaseLongreading() {  
        return this.baseLongreading;  
    }  
  
    public void setBaseLongreading(BaseLongreading baseLongreading) {  
        this.baseLongreading = baseLongreading;  
    }  
  
    public BaseTranslate getBaseTranslate() {  
        return this.baseTranslate;  
    }  
  
    public void setBaseTranslate(BaseTranslate baseTranslate) {  
        this.baseTranslate = baseTranslate;  
    }  
  
    public BaseListening getBaseListening() {  
        return this.baseListening;  
    }  
  
    public void setBaseListening(BaseListening baseListening) {  
        this.baseListening = baseListening;  
    }  
  
    public BaseCarereading getBaseCarereading1() {  
        return this.baseCarereading1;  
    }  
  
    public void setBaseCarereading1(BaseCarereading baseCarereading1) {  
        this.baseCarereading1 = baseCarereading1;  
    }  
  
    public BaseWordunderstand getBaseWordunderstand() {  
        return this.baseWordunderstand;  
    }  
  
    public void setBaseWordunderstand(BaseWordunderstand baseWordunderstand) {  
        this.baseWordunderstand = baseWordunderstand;  
    }  
  
    public BaseWriting getBaseWriting() {  
        return this.baseWriting;  
    }  
  
    public void setBaseWriting(BaseWriting baseWriting) {  
        this.baseWriting = baseWriting;  
    }  
  
    public BaseCarereading getBaseCarereading2() {  
        return this.baseCarereading2;  
    }  
  
    public void setBaseCarereading2(BaseCarereading baseCarereading2) {  
        this.baseCarereading2 = baseCarereading2;  
    }  
  
    public String getName() {  
        return this.name;  
    }  
  
    public void setName(String name) {  
        this.name = name;  
    }  
  
    public void setIsmeta(int ismeta) {  
        this.ismeta = ismeta;  
    }  
  
    public int getIsmeta() {  
        return ismeta;  
    }  
}  
複製程式碼

種群類 遺傳演算法種群類,負責存放試卷個體,並且包含相關方法。

package com.cet.tool;  
  
import com.cet.pojo.Test;  
  
/** 
 * 功能:遺傳演算法種群類 
 *  
 * @author alin 
 *  
 */  
public class Population {  
    Test[] Tests;// 個體集合  
  
    // 建立一個種群,初始化時initialise=true  
      public Population(int populationSize, boolean initialise) {  
        Tests = new Test[populationSize];  
        // 初始化種群  
        if (initialise) {  
            for (int i = 0; i < size(); i++) {  
                Test newTest = new Test();  
                newTest.getRandomTest();  
                saveTest(i, newTest);  
            }  
        }  
    }  
  
    public Test getTest(int index) {  
        return Tests[index];  
    }  
  
    // 獲取種群適應度最高的個體  
    public Test getFittest() {  
        Test fittest = Tests[0];  
        for (int i = 0; i < size(); i++) {  
            if (fittest.getFitness(Algorithm.ep) <= getTest(i).getFitness(  
                    Algorithm.ep)) {  
                fittest = getTest(i);  
            }  
        }  
        return fittest;  
    }  
  
    // 獲取種群大小  
    public int size() {  
        return Tests.length;  
    }  
  
    // 儲存試卷到種群  
    public void saveTest(int index, Test indiv) {  
        Tests[index] = indiv;  
    }  
}  
複製程式碼

操作類 遺傳演算法操作類,包含對試卷個體的交叉變異等操作

public String GA_Test(){  
        Test test = new AutoGATest().getGATest(objectService, difficulty,  
                0.8, 0.1, 5, 80, true);// 遺傳演算法自動組卷並返回試卷  
        if (test == null) {// 題型數量已經不夠用了,無法生成新的不重複的試卷  
            message = "<script>alert('Error,題庫相關難度的題型不足或者題型數量已經不夠用,無法生成新的不重複的試卷');</script>";  
            return "error";  
        }  
        test.setName(examname);//設定試題名稱  
        objectService.save(test);//儲存試題  
        return "success";  
    }  
複製程式碼

** 試題主類 通過傳入引數生成試題 **

package com.cet.tool;  
  
import com.cet.pojo.Test;  
import com.cet.service.ObjectService;  
  
/** 
 * 功能:遺傳演算法主類 
 *  
 * @author alin 
 *  
 */  
public class AutoGATest {  
  
    /** 
     * 功能:遺傳演算法生成試卷主方法 
     *  
     * @param objectService 
     * @param difficulty 
     *            試卷難度 
     * @param ep 
     *            期望難度 
     * @param uniformRate 
     *            交叉概率 
     * @param mutationRate 
     *            變異概率 
     * @param tournamentSize 
     *            淘汰陣列大小 
     * @param popSize 
     *            種群大小 
     * @param isCheck 
     *            每次交叉或變異生成的個體是否需要檢查重合,考試時檢查,練習時不需檢查 
     * @return 
     */  
    public Test getGATest(ObjectService objectService, float ep,  
            double uniformRate, double mutationRate, int tournamentSize,  
            int popSize, boolean isCheck) {  
  
        // 設定遺傳演算法相關引數  
        Algorithm.ep = ep;// 設定期望難度  
        Algorithm.uniformRate = uniformRate;// 設定交叉概率  
        Algorithm.mutationRate = mutationRate;// 設定變異概率  
        Algorithm.tournamentSize = tournamentSize;// 設定淘汰陣列大小  
        boolean isFirst = true;// 第一次進化,不進行精英主義,因為如果進行,是將初始的種群的精英放入新種群,而不會讓它進行任何交叉變異,而有可能它是與資料庫某Test重合的  
        Algorithm.objectService = objectService;  
        Population myPop = new Population(popSize, true);// 初始化一個種群  
  
        // 不斷迭代,進行進化操作。 直到找到期望的基因序列,預設都要進化一次,因為這樣,進化後的種群個體都是經過交叉變異來的,  
        // 交叉變異過程中,我進行了重複檢查,如果個體和資料庫的Test資料重合,則重新賦值一個不重複的。這樣避免了  
        // 未進化種群就找到了最優個體,而該最優個體與資料庫Test資料重合的問題  
        int generationCount = 0;  
  
        long begin = System.currentTimeMillis();  
  
        int Count = isCheck == true ? 10 : 100;  
  
        do {  
  
            if (myPop.getFittest().getFitness(Algorithm.ep) < 0.90// 種群中最好的個體適應度都低於0.9,則加大交叉概率  
                    && Algorithm.uniformRate < 0.97) {  
                System.out.print(" 加大交叉概率 ");  
                Algorithm.uniformRate += 0.07;  
            }  
            if (myPop.getFittest().getFitness(Algorithm.ep) < 0.90// 種群中最好的個體適應度都低於0.9,則加大變異概率  
                    && Algorithm.mutationRate < 0.25) {  
                System.out.println(" 加大變異概率 ");  
                Algorithm.mutationRate += 0.03;  
            }  
            if (myPop.getFittest().getFitness(Algorithm.ep) > 0.90// 種群中最好的個體適應度高於0.9,則減小交叉概率  
                    && Algorithm.uniformRate > 0.90) {  
                System.out.print(" 減小交叉概率 ");  
                Algorithm.uniformRate -= 0.07;  
            }  
            if (myPop.getFittest().getFitness(Algorithm.ep) > 0.90// 種群中最好的個體適應度高於0.9,則減小變異概率  
                    && Algorithm.mutationRate > 0.15) {  
                System.out.println(" 減小變異概率 ");  
                Algorithm.mutationRate -= 0.03;  
            }  
  
            myPop = Algorithm.evolvePopulation(myPop, isFirst, isCheck);  
            if (myPop == null) // 題型數量已經不夠用了,無法生成新的不重複的試卷  
                return null;  
            isFirst = false;  
            generationCount++;  
            System.out.println("第" + generationCount + "次進化, 適應度為: "  
                    + myPop.getFittest().getFitness(Algorithm.ep) * 100 + "%");  
  
        } while (myPop.getFittest().getFitness(Algorithm.ep) < 0.98  
                && generationCount <= Count);  
        System.out.println("用時:" + (System.currentTimeMillis() - begin)  
                / 1000.0 + "秒");  
        if (generationCount > Count) {  
            System.err.println("題庫相關難度的題型不足,無法生成新的試卷\n");  
            return null;  
        }  
        System.out.println("進化完成!");  
        System.out.println("進化總次數:" + generationCount + ",最終個體適應度:"  
                + myPop.getFittest().getFitness(Algorithm.ep) * 100 + "%"  
                + ",期望難度:" + ep + ",試卷難度:" + myPop.getFittest().getDifficulty()  
                + "\n");  
  
        return myPop.getFittest();  
    }  
}  
複製程式碼

引用類 只放一個Action方法引用

public String GA_Test(){  
        Test test = new AutoGATest().getGATest(objectService, difficulty,  
                0.8, 0.1, 5, 80, true);// 遺傳演算法自動組卷並返回試卷  
        if (test == null) {// 題型數量已經不夠用了,無法生成新的不重複的試卷  
            message = "<script>alert('Error,題庫相關難度的題型不足或者題型數量已經不夠用,無法生成新的不重複的試卷');</script>";  
            return "error";  
        }  
        test.setName(examname);//設定試題名稱  
        objectService.save(test);//儲存試題  
        return "success";  
    }  
複製程式碼

注:大二時寫的程式碼,比較渣,意思到位就行了。

相關文章