遗传算法 day 1 2023.09.13~09.14

文献题名:

遗传算法(Genetic Algorithm, GA) :在求解的过程中,进化算法首先随机生成一个种群,并对种群中的个体进行适应度计算,之后通过选择操作选择出适应度高的个体作为父代个体,然后对其进行交叉和变异等操作并生成一个新的种群(即一组新的近似解),最后通过循环上述过程,不断逼近问题近似最优解。

  (以TSP问题为例,计算适应度就是计算路线长度)

遗传算法对应概念
遗传算法试图找到给定问题的最佳解。达尔文进化论保留了种群的个体性状,而遗传算法则保留了针对给定问题的候选解集合(也称为individuals)。这些候选解经过迭代评估(evaluate),用于创建下一代解。更优的解有更大的机会被选择,并将其特征传递给下一代候选解集合。这样,随着代际更新,候选解集合可以更好地解决当前的问题。
基因型(Genotype)
在自然界中,通过基因型表征繁殖,繁殖和突变,基因型是组成染色体的一组基因的集合。
在遗传算法中,每个个体都由代表基因集合的染色体构成。例如,一条染色体可以表示为二进制串,其中每个位代表一个基因:

种群(Population)
遗传算法保持大量的个体(individuals)——针对当前问题的候选解集合。由于每个个体都由染色体表示,因此这些种族的个体(individuals)可以看作是染色体集合:


适应度函数(Fitness function)
在算法的每次迭代中,使用适应度函数(也称为目标函数)对个体进行评估。目标函数是用于优化的函数或试图解决的问题。
适应度得分更高的个体代表了更好的解,其更有可能被选择繁殖并且其性状会在下一代中得到表现。随着遗传算法的进行,解的质量会提高,适应度会增加,一旦找到具有令人满意的适应度值的解,终止遗传算法。

选择(Selection)
在计算出种群中每个个体的适应度后,使用选择过程来确定种群中的哪个个体将用于繁殖并产生下一代,具有较高值的个体更有可能被选中,并将其遗传物质传递给下一代。
仍然有机会选择低适应度值的个体,但概率较低。这样,就不会完全摒弃其遗传物质。
交叉(Crossover)
为了创建一对新个体,通常将从当前代中选择的双亲样本的部分染色体互换(交叉),以创建代表后代的两个新染色体。此操作称为交叉或重组:


突变(Mutation)
突变操作的目的是定期随机更新种群,将新模式引入染色体,并鼓励在解空间的未知区域中进行搜索。
突变可能表现为基因的随机变化。变异是通过随机改变一个或多个染色体值来实现的。例如,翻转二进制串中的一位:

遗传算法(Genetic Algorithm)详解与实现_盼小辉丶的博客-CSDN博客

【建模算法】基于遗传算法求解TSP问题(Python实现)_遗传算法python tsp_果州做题家的博客-CSDN博客

遗传算法代码:

# This is a sample Python script.

# Press Shift+F10 to execute it or replace it with your code.
# Press Double Shift to search everywhere for classes, files, tool windows, actions, and settings.
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 range(length):
            chromosome |= (1 << i) * random.randint(0,1)
        return chromosome

    def gen_population(self,length,count):
        """
        获取初始种群(一个含有count个长度为length的染色体列表)
        """
        return [self.gen_chromosome(length) for i in range(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 range(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 range(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(10,30)

        #200次迭代
    for x in range(90):
        ga.evolve()
    print (ga.result())

1.选择的作用:优胜劣汰,适者生存;

2 交叉的作用:保证种群的稳定性,朝着最优解的方向进化;

3变异的作用:保证种群的多样性,避免交叉可能产生的局部收敛。

进化策略(Evolution Strategy):

(杀死不乖的宝宝,让乖宝宝继续生乖宝宝)

(1+1)-ES

import numpy as np
import matplotlib.pyplot as plt

DNA_SIZE = 1             # DNA (real number)
DNA_BOUND = [0, 5]       # solution upper and lower bounds
N_GENERATIONS = 200
MUT_STRENGTH = 5.        # initial step size (dynamic mutation strength)


def F(x): return np.sin(10*x)*x + np.cos(2*x)*x     # to find the maximum of this function


# find non-zero fitness for selection
def get_fitness(pred): return pred.flatten()


def make_kid(parent):
    # no crossover, only mutation
    k = parent + MUT_STRENGTH * np.random.randn(DNA_SIZE)
    k = np.clip(k, *DNA_BOUND)
    return k


def kill_bad(parent, kid):
    global MUT_STRENGTH
    fp = get_fitness(F(parent))[0]
    fk = get_fitness(F(kid))[0]
    p_target = 1/5
    if fp < fk:     # kid better than parent
        parent = kid
        ps = 1.     # kid win -> ps = 1 (successful offspring)
    else:
        ps = 0.
    # adjust global mutation strength
    MUT_STRENGTH *= np.exp(1/np.sqrt(DNA_SIZE+1) * (ps - p_target)/(1 - p_target))
    return parent


parent = 5 * np.random.rand(DNA_SIZE)   # parent DNA

plt.ion()       # something about plotting
x = np.linspace(*DNA_BOUND, 200)

for _ in range(N_GENERATIONS):
    # ES part
    kid = make_kid(parent)
    py, ky = F(parent), F(kid)       # for later plot
    parent = kill_bad(parent, kid)

    # something about plotting
    plt.cla()
    plt.scatter(parent, py, s=200, lw=0, c='red', alpha=0.5,)
    plt.scatter(kid, ky, s=200, lw=0, c='blue', alpha=0.5)
    plt.text(0, -7, 'Mutation strength=%.2f' % MUT_STRENGTH)
    plt.plot(x, F(x)); plt.pause(0.05)

plt.ioff(); plt.show()

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

森屿~~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值