进化算法(GA)Python实现--以ackley函数为例

前言

        有关进化算法的介绍可以查看进化算法框架的介绍及Matlab实现(遗传算法)里面的算法介绍,这里使用Python重新实现一次。

        此内容只测试ackley函数,如果需要测试其他函数,可以在Hedar test set中的测试函数这个链接中查看函数,可以下载MATLAB的函数实现代码参考,之后也用Python重写。

1. 测试函数

1.1 ackley函数介绍

 

 1.2 ackley函数-Python计算

# ackley函数
def ackley(x):
    n = 2
    a = 20; b = 0.2; c = 2*np.pi
    s1 = 0
    s2 = 0
    for i in range(0,n):
       s1 = s1+x[i]**2
       s2 = s2+math.cos(c*x[i])
    y = -a*math.exp(-b*math.sqrt(1/n*s1))-math.exp(1/n*s2)+a+math.exp(1)
    return y

1.2 ackley函数的三维图形-Python画图

记得ackley函数也要放进去,这里的内容就不重复所以没放

import matplotlib.pyplot as plt
import numpy as np


def printAckley():
    
    x = np.arange(-30,30,0.1)
    y = np.arange(-30,30,0.1)
    x,y = np.meshgrid(x,y)
    z = np.zeros((x.shape[0],y.shape[1]),dtype=float)
    for i in range(0,x.shape[0]):
        for j in range(0,y.shape[1]):
            z[i,j] = ackley([x[i,j],y[i,j]])
    fig = plt.figure()
    ax = fig.add_subplot(111,projection='3d')
    ax.plot_surface(x,y,z)
    plt.show()

if __name__ == '__main__':
    printAckley()

2. GA的主要模块

导入的模块

import numpy as np
import math
dt = np.dtype(np.float64) # 定义np数组的数据类型,方便统一修改

2.1 初始化种群

在指定的范围的内随机生成种群

'''
 初始化种群大小
    种群大小popsize:设置种群大小
    维度dim:个体的维度
    取值范围bounds:每个个体每一维的取值范围
'''
def initPop(pop_size,dim,bounds):
    pop = np.random.rand(pop_size,dim)
    for i in range(0,dim):
        pop[:,i] = pop[:,i]*(bounds[i,1]-bounds[i,0])+bounds[i,0]
    return pop

2.2 计算种群的函数值

'''
种群计算,计算ackley函数,可以改为其他,ackley函数改一下即可
    种群pop:传入种群矩阵(数组)
    种群函数值pop_value:返回计算结果
'''
def calAckleyPop(pop):
    pop_x = pop.shape[0]
    pop_value = np.zeros((pop_x,1),dtype=dt)

    for i in range(0,pop_x):
        pop_value[i,0] = ackley(pop[i,:])
    return pop_value

2.3 计算种群的适应值

做计算得到的种群函数值做归一化处理。不一定需要做这一步,可以直接以函数值作为种群的适应值,但是到迭代后期,由于整个种群可能都趋近0,函数值作为适应值不好作为比较。

# 计算种群适应值,值进行归一化处理,,有些父代选择方式需要先做归一化处理
def calFitvalue(pop_value):
    value = 1/(pop_value+0.001) #防止分母为0,加上0.001
    max_value = max(value)
    min_value = min(value)
    fitvalue = (value-min_value)/(max_value-min_value+0.001) # 防止最大和最小是同一个值
    return fitvalue

2.4 选择父代个体

这里的父代选择方式比较简单,直接选择最佳的前N个。

# 父代选择函数,直接取前80%的个体作为父代
def selectParent(pop,fitvalue):
    # 对fitvalue进行排序,获取索引值
    fit_index = np.argsort(fitvalue,axis=0)
    fit_index = fit_index[::-1]
    pop_x,pop_y = pop.shape
    parent_num = int(pop_x//1.2)
    new_pop = np.zeros((parent_num,pop_y),dtype=dt)
    for i in  range(0,parent_num):
        new_pop[i,:] = pop[fit_index[i],:]
    return new_pop

2.5 杂交操作

# 杂交操作
def crossover(pop,pc):
    pop_x,pop_y = pop.shape
    child_pop = np.zeros((2,pop_y),dtype=dt)
    new_pop = np.zeros((1,pop_y),dtype=dt)
    for i in range(0,pop_x):
        if np.random.rand()<pc:
            parent_pop1 = pop[i,:]
            parent_pop2 = pop[np.random.randint(pop_x),:]
            n = np.random.rand()
            child_pop[0,:] = parent_pop1*n + parent_pop2*(1-n)
            child_pop[1,:] = parent_pop1*(1-n) + parent_pop2*n
            #print(pop)
            new_pop = np.concatenate((new_pop,child_pop),axis = 0)
            #print(pop)
    new_pop = np.delete(new_pop,0,axis=0)
    return new_pop

2.6 变异操作

# 变异操作
def mutation(pop,pm,bounds):
    pop_x,pop_y = pop.shape
    new_pop = np.zeros((1,pop_y),dtype=dt)
    for i in range(0,pop_x):
         # 个体变异概率
        if np.random.rand()<pm:
             # 基因变异概率
            new_pop_m = pop[i,:]
            for j in range(0,pop_y):
                if np.random.rand()<pm:
                    new_pop_m[j] = np.random.rand()*(bounds[j,1]-bounds[j,0])+bounds[j,0]
            new_pop = np.append(new_pop,[new_pop_m],axis = 0)
            
    new_pop = np.delete(new_pop,0,axis=0)
    return new_pop

2.7 种群更新操作

def updataPop(pop,pop_size,fitvalue):
    pop_x,pop_y = pop.shape
    if pop_x <= pop_size:
        return pop
    new_pop = np.zeros((pop_size,pop_y),dtype=dt)
    new_fitvalue = np.zeros((pop_size,1),dtype=dt)
    fit_index = np.argsort(fitvalue,axis=0)
    fit_index = fit_index[::-1]

    for i in range(0,pop_size):
        new_pop[i,:] = pop[fit_index[i],:]
        new_fitvalue[i,:] = fitvalue[fit_index[i],:]

    return new_pop,new_fitvalue

2.8 获取最佳个体

def bestFit(pop,fitvalue):
    fit_index = np.argsort(fitvalue,axis=0)
    fit_index = fit_index[::-1]
    best_one = pop[fit_index[-1]]
    best_fit = calAckleyPop(best_one)
    return best_one,best_fit

3. 测试结果

3.1 测试函数

def main():
    pop_size = 200
    dim = 20
    bounds = np.ones((dim,2),dtype=int)
    bounds[:,0] = -15
    bounds[:,1] = 30
    #print(bounds)
    pc = 0.8
    pm = 0.3

    pop = initPop(pop_size,dim,bounds)
    pop_value = calAckleyPop(pop)
    fitvalue = calFitvalue(pop_value)
    #print(fitvalue)
    
    for i in range(0,100):  
        perant_pop = selectParent(pop,fitvalue) # 选择父代
        pop_c = crossover(perant_pop,pc)        # 杂交操作
        new_pop = np.concatenate((pop_c,pop))   # 合并种群和杂交获得的后代pop_c得到新种群
        pop_m = mutation(new_pop,pm,bounds)     # 新种群做变异操作,得到变异种群pop_c
        new_pop = np.concatenate((pop_m,new_pop)) # 合并pop_c新种群
        
        new_pop_value = calAckleyPop(new_pop)   # 计算新种群的函数值
        fitvalue = calFitvalue(new_pop_value)   # 计算种群适应值
        pop,fitvalue= updataPop(new_pop,pop_size,fitvalue) # 更新种群
        
    best_one,best_fit = bestFit(pop,fitvalue)
    print(best_fit[0,0])

if __name__ == '__main__':
    for i in range(0,20):
        main()

3.2 结果

4.440892098500626e-16 这个值在Python中好像就是最低值,对这个没有去追究。Python数据精度相关的知识了解并不多。正在学习中,内容仅作为参考。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值