前言
有关进化算法的介绍可以查看进化算法框架的介绍及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数据精度相关的知识了解并不多。正在学习中,内容仅作为参考。