1. 程式人生 > >遺傳演算法-python實現

遺傳演算法-python實現

已經調通,並有大量註釋

# encoding=utf-8
import math
import random
import operator


class GA():
    def __init__(self, length, count):
        # 染色體長度
        self.length = length
        # 種群中的染色體數量
        self.count = count
        # 隨機生成初始種群
        self.population = self.gen_population(length, count)
    def evolve(self, retain_rate=0.2, random_select_rate=0.5, mutation_rate=0.01):
        """
        進化
        對當前一代種群依次進行選擇、交叉並生成新一代種群,然後對新一代種群進行變異
        """
        parents = self.selection(retain_rate, random_select_rate)
        self.crossover(parents)
        self.mutation(mutation_rate)

    def gen_chromosome(self, length):
        """
        隨機生成長度為length的染色體,每個基因的取值是0或1
        這裡用一個bit表示一個基因
        """
        chromosome = 0
        for i in xrange(length):
            # 終於明白了  這裡的或是整個二進位制比對的或|,比如10和1或下來的結果是11,  1001和101或的結果是1101,所以此處是個不斷隨機或出來的長度
            chromosome |= (1 << i) * random.randint(0, 1)  # 這裡每次左移, 隨機生成一個0或者1的數字,這樣不斷左移生成給定長度的二進位制染色體

        print '{0:b}'.format(chromosome)
        return chromosome

    def gen_population(self, length, count):
        """
        獲取初始種群(一個含有count個長度為length的染色體的列表)
        """
        return [self.gen_chromosome(length) for i in xrange(count)]

    def fitness(self, chromosome):
        """
        計算適應度,將染色體解碼為0~9之間數字,代入函式計算
        因為是求最大值,所以數值越大,適應度越高
        """
        x = self.decode(chromosome)  # 對於一個基因,代入二進位制值進行解碼,然後使用適應函式求出適應值
        return x + 10 * math.sin(5 * x) + 7 * math.cos(4 * x)

    def selection(self, retain_rate, random_select_rate):
        """
        選擇
        先對適應度從大到小排序,選出存活的染色體
        再進行隨機選擇,選出適應度雖然小,但是倖存下來的個體
        """
        # 對適應度從大到小進行排序
        graded = [(self.fitness(chromosome), chromosome) for chromosome in self.population]  # 求出所有染色體的適應值列表
        graded = [x[1] for x in sorted(graded, reverse=True)]  # 從小到大排序,形成新列表
        # 選出適應性強的染色體
        retain_length = int(len(graded) * retain_rate)  # 根據比例值  找到前。個適應性強的染色體 作為下一代的父母親
        parents = graded[:retain_length]
        # 選出適應性不強,但是倖存的染色體        從後面中  隨機選取一比例   也放到父母親中
        for chromosome in graded[retain_length:]:
            if random.random() < random_select_rate:
                parents.append(chromosome)
        return parents

    def crossover(self, parents):
        """
        染色體的交叉、繁殖,生成新一代的種群
        """
        # 新出生的孩子,最終會被加入存活下來的父母之中,形成新一代的種群。
        children = []
        # 需要繁殖的孩子的量      差值,就是要交叉生成的目標數
        target_count = len(self.population) - len(parents)
        # 開始根據需要的量進行繁殖
        while len(children) < target_count:
            male = random.randint(0, len(parents) - 1)
            female = random.randint(0, len(parents) - 1)
            if male != female:  # 父母親序號不能相同
                # 隨機選取交叉點
                cross_pos = random.randint(0, self.length)
                # 生成掩碼,方便位操作
                mask = 0
                for i in xrange(cross_pos):
                    mask |= (1 << i)
                male = parents[male]
                female = parents[female]
                # 孩子將獲得父親在交叉點前的基因和母親在交叉點後(包括交叉點)的基因
                child = ((male & mask) | (female & ~mask)) & ((1 << self.length) - 1)
                children.append(child)
        # 經過繁殖後,孩子和父母的數量與原始種群數量相等,在這裡可以更新種群。
        self.population = parents + children

    def mutation(self, rate):
        """
        變異
        對種群中的所有個體,隨機改變某個個體中的某個基因
        """
        for i in xrange(len(self.population)):
            if random.random() < rate:
                j = random.randint(0, self.length - 1)
                self.population[i] ^= 1 << j

    def decode(self, chromosome):
        """
        解碼染色體,將二進位制轉化為屬於[0, 9]的實數
        """
        return chromosome * 9.0 / (2 ** self.length - 1)

    def result(self):
        """
        獲得當前代的最優值,這裡取的是函式取最大值時x的值。
        """
        graded = [(self.fitness(chromosome), chromosome) for chromosome in self.population]
        graded = [x[1] for x in sorted(graded, reverse=True)]
        return ga.decode(graded[0])


if __name__ == '__main__':
    # 染色體長度為17, 種群數量為300
    ga = GA(17, 20)
    # 200次進化迭代
    for x in xrange(500):
        ga.evolve()
    print ga.result()