进化算法(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数据精度相关的知识了解并不多。正在学习中,内容仅作为参考。

 

  • 6
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,下面是使用Python实现Ackley函数优化问题的遗传算法的步骤: 1.导入必要的库 ```python import numpy as np import matplotlib.pyplot as plt ``` 2.定义Ackley函数 ```python def ackley(x): n = len(x) sum1 = sum([x[i] ** 2 for i in range(n)]) sum2 = sum([np.cos(2 * np.pi * x[i]) for i in range(n)]) return -20 * np.exp(-0.2 * np.sqrt(sum1 / n)) - np.exp(sum2 / n) + 20 + np.exp(1) ``` 3.初始化种群 ```python def init_population(pop_size, chromosome_length): population = np.random.uniform(-32.768, 32.768, size=(pop_size, chromosome_length)) return population ``` 4.计算适应度函数 ```python def cal_fitness(population): fitness = np.zeros(population.shape[0]) for i in range(population.shape[0]): fitness[i] = ackley(population[i]) return fitness ``` 5.选择操作 ```python def selection(population, fitness): idx = np.random.choice(np.arange(population.shape[0]), size=2, replace=False, p=fitness / np.sum(fitness)) return population[idx] ``` 6.交叉操作 ```python def crossover(parents, pc): if np.random.rand() < pc: child1 = np.zeros(parents[0].shape) child2 = np.zeros(parents[1].shape) pos = np.random.randint(1, parents[0].shape[0] - 1) child1[:pos] = parents[0][:pos] child1[pos:] = parents[1][pos:] child2[:pos] = parents[1][:pos] child2[pos:] = parents[0][pos:] return child1, child2 else: return parents[0], parents[1] ``` 7.变异操作 ```python def mutation(child, pm): if np.random.rand() < pm: pos = np.random.randint(child.shape[0]) child[pos] = np.random.uniform(-32.768, 32.768) return child ``` 8.遗传算法函数 ```python def genetic_algorithm(pop_size, chromosome_length, pc, pm, max_iter): population = init_population(pop_size, chromosome_length) fitness = cal_fitness(population) best_idx = np.argmin(fitness) best_individual = population[best_idx] best_fitness = fitness[best_idx] for i in range(max_iter): new_population = np.zeros(population.shape) for j in range(int(pop_size / 2)): parents = selection(population, fitness) child1, child2 = crossover(parents, pc) child1 = mutation(child1, pm) child2 = mutation(child2, pm) new_population[j * 2] = child1 new_population[j * 2 + 1] = child2 population = new_population fitness = cal_fitness(population) best_idx = np.argmin(fitness) if fitness[best_idx] < best_fitness: best_individual = population[best_idx] best_fitness = fitness[best_idx] return best_individual, best_fitness ``` 9.测试代码 ```python best_individual, best_fitness = genetic_algorithm(pop_size=100, chromosome_length=2, pc=0.8, pm=0.1, max_iter=100) print("最优解:", best_individual) print("最优解的适应度:", best_fitness) ``` 运行以上代码即可得到Ackley函数的最优解和最优解的适应度。 希望我的回答对你有所帮助!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值