python简易实现遗传算法求函数极值

基本思想

遗传算法(Genetic Algorithm, GA)
顾名思义是模仿生物的遗传学机理进行计算模拟最优解的过程。
将生物种群特征与问题进行对应
一个染色体代表问题的一个解(一个染色体含有多个基因)
一个基因代表问题的一个决策变量
多个个体构成一个种群,多组解构成解的种群。
我们使问题解的种群不断的优胜劣汰,像自然界的自然选择一般,直到最后剩下一个获胜的最优解,便结束了问题的求解。

算法流程

1. 初始化

随机生成一个种群。其中基因需要编码。
常用的编码方式有二进制编码法,浮点编码法,符号编码法。
今天先来做个二进制编码法,其解码、编码、交叉、变异等操作简单易行,但是由于随机性,局部搜索能力较差。
“与人类的染色体不同,我们假设只有“0”和“1”两种碱基,因此只需要将我们的决策变量进行二进制编码即可获得基因序列。”

2. 评估个体适应度

可以直接用函数值作为适应度,我们要找最小值嘛。

3. 进行自然选择

  • 计算出适应度综合 Σ f i \Sigma f_i Σfi
  • 计算出相对适应度大小 f i / Σ f i f_i/\Sigma f_i fi/Σfi
  • 产生随机出,确定各个个体被选中的次数

4. 进行组合交叉

选定一个交配概率pc

  • 群体随机配对
  • 随机设定交叉点
  • 互换染色体部分基因

5. 进行变异

  • 随机产生变异点
  • 根据变异概率阈值pm使原有基因突变
    在这里插入图片描述

终止条件

可以设置若干迭代次数作为终止条件。

目标问题

emmm,是在csdn的必问上看到一个问题,要求寻找目标函数的全局最小值
在这里插入图片描述
就打算拿这个试一下

算法实现

初始化

首先初始化种群,如果是n维输入的话,每个染色体上都应该有n个基因,分别代表 x 1 . . . . . x n x_1.....x_n x1.....xn
这个时候需要先考虑一些如何进行二进制编码。
x的范围是-32.77到32.77,我选用13位二进制数来编码。

将一个二进制串代表的二进制数转化为十进制数:
( b 0 . . . . . . b n ) = ( Σ i = 0 n b i 2 i ) = x ′ (b_0......b_n)=(\Sigma^n_{i=0}b_i2^i)=x' (b0......bn)=(Σi=0nbi2i)=x
对应区间内的实数:
x = − 32.77 + x ′ 65.54 2 13 − 1 x = - 32.77 + x'\frac{65.54}{2^{13}-1} x=32.77+x213165.54
那么有还原的函数

def translation(L):#将二进制编码还原为变量
    n = 0
    for i in range(13):
        n += L[i]*pow(2,i)
    
    return -32.77 + n * (65.54/k)

适应度函数与自然选择

这里用比较简单的选择方法,每个个体被选中的概率都是自身的适应度除以总适应度的和。
α i = F i Σ F \alpha_i = \frac{F_i}{\Sigma F} αi=ΣFFi
直接使用我们的目标函数,emmm好像不太成,这样的话越小的值适应度越小了,理论上应该是适应度越大才对。

def f(x):#目标函数
    n = len(x)
    return -20*np.exp(-0.2*np.sqrt(1/n*sum(np.power(x,2))))\
        -np.exp(1/n*sum(np.cos(2*pi*x))) + 20

不过那也好说,我们可以找出来所有个体的最大值,然后用这个值减去各个个体的函数值作为其适应度,这样最大的一个的适应度就是0,自然死亡。

def fitness(popular):
    fit = [0] * len(popular)
    n = len(popular[0])//13 #数据维度
    maxfit = -1e5
    for i in range(popular):
        x = []
        for j in range(n):
            x.append(translation(i[j:j+13]))
        fit[i] = f(np.array(x))
        if fit[i] > maxfit:
            maxfit = fit[i]
    for i in range(len(fit)):
        fit[i] = maxfit - fit[i]
    return fit

接下来就是轮盘赌了,计算出所有的适应度然后根据概率判断新的种群中的个体


def choose(popular):#进行自然选择
    popular_len = len(popular)#个体个数
    survival_rate = []
    for i in range(popular_len):
        survival_rate.append(random.random())
    
    fit = fitness(popular)#每个个体的存活率
    best_individual = popular[fit.index(max(fit))]#保存下当前种群最优个体(其实写这里不太会)
    survival_rate.sort()
    fitin = 0
    newin = 0
    newpopular = popular

    # 开始轮盘赌
    # 结束之后,适应度更高的个体在新种群中应该更多
    while newin < popular_len:
        if survival_rate[newin] < fit[fitin]:
            newpopular[newin] = popular[fitin]
            newin += 1#旋转轮盘
        else:
            fitin += 1#旋转轮盘
    popular = newpopular
    return best_individual

交叉

取交叉率pc=0.5

def crossover(popular,pc):#pc为交叉率
    popular_len=len(popular)

    for i in range(popular_len-1):
        crosspoint = random.randint(0,len(popular[0]))#随机生成交叉点
        # 一个个体染色体长度为len(popular[0]),crosspoint为交换位置
        #接下来我们让第i个个体和第i+1个个体发生交叉
        t1 =[]
        t2= []
        t1.extend(popular[i][0:crosspoint])#i的前半段
        t1.extend(popular[i+1][crosspoint:-1])#i+1的后半段
        t2.extend(popular[i+1][0:crosspoint])#i+1的前半段
        t2.extend(popular[i][crosspoint:-1])#i的后半段
        # 放回种群
        popular[i] = t1 
        popular[i+1] = t2

变异

取变异率0.01吧

def mutation(popular,pm):#pm为变异率
    popular_len=len(popular)
    chromosome_len = len(popular[0])
    for i in range(popular_len):
        if random.random()>pm:#大于阈值则发生变异
            mutation_point = random.randint(0,chromosome_len-1)
            #发生变异
            if popular[i][mutation_point] == 1:
                popular[i][mutation_point] = 0
            else:
                popular[i][mutation_point] = 1

最后连起来实现迭代

def GA(n):
    ## 初始化种群
    popular_size = 100#种群大小
    chromosome_length = n*13#染色体大小
    popular = []
    for i in range(popular_size):
        individual = []
        for j in range(chromosome_length):#生成随机基因
            individual.append(random.randint(0,1))
        popular.append(individual)#向种群添加一个个体
    # 种群初始化完成
    best_individual = []
    for i in range(200):#迭代200次
        best_individual.append( choose(popular) ) #保存下最优个体
        crossover(popular,0.5)
        mutation(popular,0.01)
    solutions = []#解的迭代过程
    for i in best_individual:
        s = []
        for j in range(n):
           s.append(translation( i[13*j:13*j+13] ))
        #还原为了十进制数   
        solutions.append(s)
    return solutions#保存的是各次迭代发现的最优解,最后一个是结果

代码

python代码

  • 5
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论
遗传算法是一种基于自然选择和遗传学原理的优化算法,可以用于求解函数极值问题。下面是遗传算法求解三元函数极值的步骤: 1.定义适应度函数:对于三元函数f(x1,x2,x3)=x1*x1-x1*x2+x3,我们可以将其作为适应度函数,即fitness(x1,x2,x3)=f(x1,x2,x3)。 2.初始化种群:随机生成一定数量的个体,每个个体由三个实数编码表示,即x1、x2、x3。 3.选择操作:采用轮盘赌选择算子,根据个体适应度大小选择优秀的个体。 4.交叉操作:采用单点交叉算子,对选出的个体进行交叉操作,生成新的个体。 5.变异操作:对新生成的个体进行变异操作,增加种群的多样性。 6.评估函数:计算每个个体的适应度值。 7.选择优秀个体:根据适应度值选择优秀的个体。 8.重复执行步骤3-7,直到达到预设的迭代次数或找到最优解。 下面是Python代码实现: ```python import random # 定义适应度函数 def fitness(x1, x2, x3): return x1 * x1 - x1 * x2 + x3 # 初始化种群 def init_population(pop_size): population = [] for i in range(pop_size): x1 = random.uniform(-10, 10) x2 = random.uniform(-10, 10) x3 = random.uniform(-10, 10) population.append((x1, x2, x3)) return population # 选择操作 def selection(population): fitness_list = [fitness(*individual) for individual in population] total_fitness = sum(fitness_list) probability_list = [fitness / total_fitness for fitness in fitness_list] selected_population = [] for i in range(len(population)): selected_individual = random.choices(population, weights=probability_list)[0] selected_population.append(selected_individual) return selected_population # 交叉操作 def crossover(population): offspring_population = [] for i in range(len(population)): parent1 = population[i] parent2 = random.choice(population) crossover_point = random.randint(0, 2) offspring = parent1[:crossover_point] + parent2[crossover_point:] offspring_population.append(offspring) return offspring_population # 变异操作 def mutation(population, mutation_rate): mutated_population = [] for individual in population: if random.random() < mutation_rate: mutated_individual = list(individual) mutated_individual[random.randint(0, 2)] += random.uniform(-1, 1) mutated_population.append(tuple(mutated_individual)) else: mutated_population.append(individual) return mutated_population # 遗传算法求解三元函数极值 def genetic_algorithm(pop_size, max_iter, mutation_rate): population = init_population(pop_size) for i in range(max_iter): selected_population = selection(population) offspring_population = crossover(selected_population) mutated_population = mutation(offspring_population, mutation_rate) population = mutated_population best_individual = max(population, key=lambda x: fitness(*x)) return best_individual # 测试 best_individual = genetic_algorithm(100, 1000, 0.1) print("最优解:", best_individual) print("最优解对应的函数值:", fitness(*best_individual)) ```
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

豆沙粽子好吃嘛!

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

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

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

打赏作者

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

抵扣说明:

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

余额充值