遗传算法python

本文详细描述了如何使用遗传算法,结合单切点交叉和双切点交叉,以及轮盘赌选择和变异操作,求解一个多变量函数的最大值。通过逐步展示关键步骤,包括初始化种群、适应值评估、选择、交叉和变异,最终优化种群以找到适应值最高的解。
摘要由CSDN通过智能技术生成

假设函数eq?y%3Df%28x_%7B1%7D%2Cx_%7B2%7D%2Cx_%7B3%7D%2Cx_%7B4%7D%29%3D%5Cfrac%7B1%7D%7B1+%7Cx_%7B1%7D%7C+%7Cx_%7B2%7D%7C+%7Cx_%7B3%7D%7C+%7Cx_%7B4%7D%7C%7D其中eq?-10%5Cleq%20x_%7B1%7D%2Cx_%7B2%7D%2Cx_%7B3%7D%2Cx_%7B4%7D%5Cleq%2010试用遗传算法求解y的最大值,请仿照例4.1参考课件第三章遗传算法的流程”)写出关键的求解步骤

import random
import math
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus']=False


'''产生初始种群'''
def initialpopulation(NP,n,x0,x1):
    '''NP代表种群规模,n代表目标函数的未知量的个数;
       x0代表未知数取值的下限,x1代表未知数取值的上限'''
    initial=[]
    for i in range(NP):
        n_initial=[random.uniform(x0,x1) for j in range(n)]
        initial.append(n_initial)
    return initial


'''标定适值函数'''
def fitnessfunction(X):
    '''X代表存储各个未知量的取值的列表'''
    return 1/(math.sqrt(X[0]**2)+math.sqrt(X[1]**2)+math.sqrt(X[2]**2)+math.sqrt(X[3]**2)+1)


'''采用轮盘赌选择算法选择个体'''
def selection(NP,X0):
    '''NP代表种群规模,X0代表种群'''

    #计算种群中各个个体的适应值
    value=[]
    for i in range(NP):
        value.append(fitnessfunction(X0[i]))


    '''计算适应度和累计概率函数'''
    #计算选择概率
    fsum=0
    for i in range(NP):
        fsum=fsum+value[i]**2
    value_ratio=[]
    for i in range(NP):
        value_ratio.append((value[i]**2)/fsum)

    #计算累加概率
    value_ratio_add=[]
    for i in range(NP):
        if i==0:
            value_ratio_add.append(value_ratio[i])
        else:
            value_ratio_add.append(value_ratio_add[i-1]+value_ratio[i])


    #产生[0,1]之间的随机数,进行NP次轮转
    random_ratio=[random.uniform(0,1) for i in range(NP)]

    #进行轮盘赌选择
    choose_index=[]    #从0开始计
    value_ratio_add0=[0,*value_ratio_add]   #在列表value_ratio_add的最前面加上一个0
    for i in range(NP):
        for j in range(NP):
            if random_ratio[i]>=value_ratio_add0[j] and random_ratio[i]<value_ratio_add0[j+1]:
                choose_index.append(j)
                break

    #得到经过轮盘赌选择算法后的种群
    population=[X0[i] for i in choose_index]

    return population


'''遗传运算——单切点交叉'''
def crossover1(X0,pc,NP,n):
    '''X0代表种群,pc代表交叉概率,NP代表种群规模,n代表染色体上的基因数目'''

    #对每个染色体生成一个[0,1]之间的随机数
    random_crossover=[random.uniform(0,1) for i in range(NP)]

    #判断哪些染色体进行交叉运算
    crossover_index=[]        #种群中进行交叉运算的染色体的索引值
    for i in range(NP):
        if random_crossover[i]<pc:
            crossover_index.append(i)

    #判断初步确定的需要交叉的染色体个数,如果为奇数,则最后一个染色体不进行交叉运算
    if (len(crossover_index)%2)!=0:
        crossover_index.pop()
        crossover_index=crossover_index

    #进行单切点交叉
    if len(crossover_index)!=0:
        randint_index=[random.randint(0,n-2) for i in range(int(len(crossover_index)/2))]   #选择切点
        for i in range(0,len(crossover_index),2):
            crossover1=X0[crossover_index[i]]
            crossover2=X0[crossover_index[i+1]]
            crossoverindex=randint_index[int(i/2)]
            #分割
            crossover1_0=[crossover1[j] for j in range(crossoverindex+1)]
            crossover1_1=[crossover1[j] for j in range(crossoverindex+1,n)]
            crossover2_0 = [crossover2[j] for j in range(crossoverindex + 1)]
            crossover2_1 = [crossover2[j] for j in range(crossoverindex + 1, n)]
            #交换
            X0[crossover_index[i]]=[*crossover1_0,*crossover2_1]
            X0[crossover_index[i+1]]=[*crossover2_0,*crossover1_1]

    #返回进行单切点交叉后的种群
    return X0


'''遗传运算——双切点交叉'''
def crossover2(X0,pc,NP,n):
    '''X0代表种群,pc代表交叉概率,NP代表种群规模,n代表染色体上的基因数目'''

    # 对每个染色体生成一个[0,1]之间的随机数
    random_crossover=[random.uniform(0, 1) for i in range(NP)]

    # 判断哪些染色体进行交叉运算
    crossover_index=[]  # 种群中进行交叉运算的染色体的索引值
    for i in range(NP):
        if random_crossover[i]<pc:
            crossover_index.append(i)

    # 判断初步确定的需要交叉的染色体个数,如果为奇数,则最后一个染色体不进行交叉运算
    if (len(crossover_index)%2)!=0:
        crossover_index.pop()
        crossover_index=crossover_index

    #进行双切点交叉
    if len(crossover_index)!=0:
        randint_index=[sorted(random.sample([i for i in range(0,n-1)],2)) for i in range(int(len(crossover_index)/2))]
        for i in range(0,len(crossover_index),2):
            crossover1=X0[crossover_index[i]]
            crossover2=X0[crossover_index[i+1]]
            crossoverindex=randint_index[int(i/2)]
            #分割
            crossover1_1=[crossover1[j] for j in range(crossoverindex[0]+1)]
            crossover1_2=[crossover1[j] for j in range(crossoverindex[0]+1,crossoverindex[1]+1)]
            crossover1_3=[crossover1[j] for j in range(crossoverindex[1]+1,n)]
            crossover2_1=[crossover2[j] for j in range(crossoverindex[0]+1)]
            crossover2_2=[crossover2[j] for j in range(crossoverindex[0]+1,crossoverindex[1]+1)]
            crossover2_3=[crossover2[j] for j in range(crossoverindex[1]+1,n)]
            #交换
            X0[crossover_index[i]]=[*crossover1_1,*crossover2_2,*crossover1_3]
            X0[crossover_index[i+1]]=[*crossover2_1,*crossover1_2,*crossover2_3]


    #返回进行双切点交叉后的种群
    return X0



'''进行遗传运算——变异'''
def mutation(X0,pm,NP,n,x0,x1):
    '''X0代表种群,pm代表交叉概率,NP代表种群规模,n代表染色体上的基因数目
       x0代表未知数取值的下限,x1代表未知数取值的上限'''

    #生成在[0,1]上的随机数列表
    random_gene=[[random.uniform(0,1) for i in range(n)] for j in range(NP)]

    #进行变异运算
    for i in range(NP):
        for j in range(n):
            if random_gene[i][j]<pm:
                X0[i][j]=random.uniform(x0,x1)

    #返回经过变异操作后的种群
    return X0


'''计算种群中所有个体的适应值并返回最大值'''
def fitnessmax(X0,NP):
    '''X0代表种群,NP代表种群规模'''

    #计算种群中各个个体的适应值
    value=[]
    for i in range(NP):
        value.append(fitnessfunction(X0[i]))
    value_max=max(value)
    #适应值最大所对应的索引值
    index_max=value.index(max(value))
    #适应值最大所对应的染色体
    X0_max=X0[index_max]

    return value_max,X0_max


'''计算种群的平均适应值'''
def fitness_avg(X0,NP):
    '''X0代表种群,NP代表种群规模'''

    #计算种群中各个个体的适应值
    value=[]
    for i in range(NP):
        value.append(fitnessfunction(X0[i]))
    #平均适应值
    value_avg=sum(value)/NP

    return value_avg


'''使用单切点交叉的遗传算法'''
def GA1(NP,NG,n,x0,x1,pc,pm):
    '''NP代表种群规模,NG代表最大代数,n代表一个染色体的基因数
       x0代表未知数取值的下限,x1代表未知数取值的上限
       pc代表交叉概率,pm代表变异概率'''

    #遗传算法——单切点交叉
    print("----------------------------------------------------------遗传算法(单切点交叉)----------------------------------------------------------")

    #产生初始种群
    X0=initialpopulation(NP,n,x0,x1)

    #存储每一代最大适应值和对应的函数值的列表
    fitnessmax_list=[]
    X0max_list=[]

    #历史最大适应值和对应的函数值
    history_max=0
    history=[]
    history_X0=[]

    for i in range(NG):
        '''得到种群的最大适应值和对应的染色体'''
        value_max,valueX0_max=fitnessmax(X0,NP)
        fitnessmax_list.append(value_max)
        X0max_list.append(valueX0_max)
        if i==0:
            history_max=value_max
            history.append(history_max)
            history_X0.append(valueX0_max)
        else:
            if value_max>=history_max:
                history_max=value_max
                history.append(history_max)
                history_X0.append(valueX0_max)
            else:
                history.append(history_max)
                history_X0.append(history_X0[i-1])
        print("第{}代:{}     value_max={}".format(i + 1, history_X0[i], history[i]))


        '''选择'''
        X1=selection(NP,X0)

        '''双切点交叉运算'''
        X2=crossover1(X1,pc,NP,4)

        '''变异运算'''
        X3=mutation(X2,pm,NP,4,-10,10)

        X0=X3

    print("最优解Best={}".format(history[-1]))
    print("---------------------------------------------------------------进程结束---------------------------------------------------------------")


    '''绘制随着代数的增加每一代的最大适应值和历史最大适应值的变化'''
    ax1=plt.subplot(111)
    ax1.plot(range(1,NG+1),fitnessmax_list,c='plum',label="每一代的最大适应值")
    ax1.set_ylabel("适应值")
    ax1.set_xlabel("代数")
    plt.title("遗传算法(单切点交叉)每一代的最大适应值随代数的变化")
    ax1.legend()
    plt.show()
    ax2=plt.subplot(111)
    ax2.plot(range(1,NG+1),history,c='orange',label="历史最大适应值")
    ax2.set_ylabel("适应值")
    ax2.set_xlabel("代数")
    plt.title("遗传算法(单切点交叉)的优化过程")
    ax2.legend()
    plt.show()

    return fitnessmax_list[-1],history[-1],X0max_list[-1],history_X0[-1]


'''使用双切点交叉的遗传算法'''
def GA2(NP,NG,n,x0,x1,pc,pm):
    '''NP代表种群规模,NG代表最大代数,n代表一个染色体的基因数
       x0代表未知数取值的下限,x1代表未知数取值的上限
       pc代表交叉概率,pm代表变异概率'''

    #遗传算法——单切点交叉
    print("----------------------------------------------------------遗传算法(双切点交叉)----------------------------------------------------------")

    #产生初始种群
    X0=initialpopulation(NP,n,x0,x1)

    #存储最大适应值和对应的函数值的列表
    fitnessmax_list=[]
    X0max_list=[]

    #历史最大适应值
    history_max=0
    history=[]
    history_X0=[]

    for i in range(NG):
        '''得到种群的最大适应值和对应的染色体'''
        value_max,valueX0_max=fitnessmax(X0,NP)
        fitnessmax_list.append(value_max)
        X0max_list.append(valueX0_max)
        if i==0:
            history_max=value_max
            history.append(history_max)
            history_X0.append(valueX0_max)
        else:
            if value_max>=history_max:
                history_max=value_max
                history.append(history_max)
                history_X0.append(valueX0_max)
            else:
                history.append(history_max)
                history_X0.append(history_X0[i-1])
        print("第{}代:{}     value_max={}".format(i + 1, history_X0[i], history[i]))



        '''选择'''
        X1=selection(NP,X0)

        '''双切点交叉运算'''
        X2=crossover2(X1,pc,NP,4)

        '''变异运算'''
        X3=mutation(X2,pm,NP,4,-10,10)

        X0=X3

    print("最优解Best={}".format(history[-1]))
    print("---------------------------------------------------------------进程结束---------------------------------------------------------------")


    '''绘制随着代数的增加最大适应值的变化'''
    ax1=plt.subplot(111)
    ax1.plot(range(1,NG+1),fitnessmax_list,c='plum',label="每一代的最大适应值")
    ax1.set_ylabel("适应值")
    ax1.set_xlabel("代数")
    plt.title("遗传算法(双切点交叉)每一代的最大适应值随代数的变化")
    ax1.legend()
    plt.show()
    ax2=plt.subplot(111)
    ax2.plot(range(1,NG+1),history,c='orange',label="历史最大适应值")
    ax2.set_ylabel("适应值")
    ax2.set_xlabel("代数")
    plt.title("遗传算法(双切点交叉)的优化过程")
    ax2.legend()
    plt.show()

    return fitnessmax_list[-1],history[-1],X0max_list[-1],history_X0[-1]


'''主函数'''
if __name__=="__main__":

    '''规定最大代数'''
    NG=1000

    '''规定种群规模'''
    NP=100

    '''规定交叉率'''
    pc=0.9

    '''规定变异率'''
    pm=0.1

    '''规定一个染色体上的基因数'''
    n=4

    '''规定未知数的下限'''
    x0=-10

    '''规定未知数的上限'''
    x1=10

    '''存储遗传算法中单切点交叉和双切点交叉最后得到的最大适应值及对应的未知数取值'''
    fitness_max=[]
    fitnessX0_max=[]

    '''进行单切点交叉的遗传算法'''
    value_max1,historymax1,valueX0_max1,historymaxX0_1=GA1(NP,NG,n,x0,x1,pc,pm)
    fitness_max.append(historymax1)
    fitnessX0_max.append(historymaxX0_1)

    '''进行双切点交叉的遗传运算'''
    value_max2,historymax2,valueX0_max2,historymaxX0_2=GA2(NP,NG,n,x0,x1,pc,pm)
    fitness_max.append(historymax2)
    fitnessX0_max.append(historymaxX0_2)

    print("单切点交叉的最优解:{}\t对应的未知数取值:{}\n双切点交叉的最优解:{}\t对应的未知数取值:{}".format(fitness_max[0],fitnessX0_max[0],fitness_max[1],fitnessX0_max[1]))

第一次运行的结果:

00f5ec8e14354437af7632dcb58c9b1d.png

7dabe981c88c4faf8bbb529221cd3fe9.png 041e2962d9b8474f8df00772fb0670a5.png f4ac29b9ddc8473387ab0b1087b0aece.png

6f4f42b496fa467e9fbb9d175ecc83a3.png 

第二次运行的结果:
c61fca1b55d24fb18f7de2b694f3d4c6.png 294be572728042188ffd87a76ac3cf5c.png

66b36555b0764e3a99cb1f236c9523b9.png 0c0df7186d6e4689bd7740dee71dc046.png

0ce4ee2ab02845f8aa970d24b3fd0ce8.png

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

天下弈星~

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

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

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

打赏作者

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

抵扣说明:

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

余额充值