差分进化算法
算法思路:
1.算法流程图:
2.算法思想:
①确定目标函数 例如求f(x)=x^2+x/2+x^2/3函数的最小值,x的取值范围为(-20,+20)
②初始化一些初始解 也就是先**随机**生成一些x
③求初始解的适应度值 也就是将随机生成的解带入到函数中去求出函数值
④选择适应度最好的解 选择出上述操作之后函数值最好的n(n靠自己定义)个解(也就是x)
⑤对上述选择的解进行交叉、变异操作(这两个操作下面细讲)
⑥对交叉、变异后的新解进行边界处理 因为我们x已经定义了取值范围,x不能超出此范围取值
⑦重新求出经过操作后的解的适应度 也就是求出新解的函数值
⑧判断是否已经满足结束条件,否则返回第四步
3.算法重要参数
①种群大小P(population) 也就是随机生成解的个数
②个体维度D(dimension) 也就是随机生成解的维度大小(维度指的是很可能x并不是单指一个实数,有可能是指一个矢量,也有可能指的是矩阵中的一行或一列)
③变异算子CR1 进行变异操作时需要的参数
④交叉算子CR2 进行交叉操作时需要的参数
⑤迭代次数G(generation) 一共需要循环的次数
变异交叉操作详解
变异:生物学意义上也就是进行基因变异,在该算法中相当于改变个体中的某些部分。例如初始x=[1,2,3,4,5,6]为一个6维,经过变异操作后可能变成[1,21,3,4,56,65]
交叉:生物学上叫做基因交叉,在该算法中相当于两个多维度的个体相互交换某些维度的数值。例如x1=[1,9,8,7,12] x2=[98,54,63,21,1]对x1、x2进行1、3、5维度的交叉,得出一个新的x1`=[98,9,63,7,1],x2`=[1,54,8,21,12]
变异以及交叉操作技术后得出新的个体,然后带入到操作流程中
代码示例(详细注解)
导入代码所需要的库
import random
import numpy as np
import matplotlib.pyplot as plt
plt.rc('font',family='KaiTi') #中文显示问题
定义目标函数(也就是适应度函数)
def f1(x):
return np.sum((x - 1) **2 )#求(x-1)的平方的最小值
初始化算法所需要参数
population_size = 100 #定义种群规模,也就是一共有多少个个体
dimension = 20 #定义个体维度
#定义个体边界值
lower_band = -100
upper_band = 100
F = random.uniform(0.2,0.8) #随机生成一个实数来作为差分权重
CR1 = 0.2 #定义交叉概率
CR2 = 0.2 #定义变异因子
generations = 100
#初始化种群
population = np.random.uniform(lower_band,upper_band,(population_size,dimension))
#查看population种群
population
array([[ 61.08988255, 93.58656325, 25.10739419, ..., -90.79082588,
-17.43888371, 64.42807136],
[ 26.85052576, 94.50131987, 58.80338945, ..., -24.7227089 ,
-46.12172234, -84.25432156],
[-92.78709384, -37.43311139, -17.98510195, ..., -7.85818691,
95.31387058, -77.89638401],
...,
[ 68.33198157, -2.60425885, -24.06922746, ..., -53.12641888,
19.23669603, -14.28417421],
[ 3.50878467, -19.40844065, -76.05249883, ..., 9.11712924,
19.42098486, 58.17541794],
[-59.37100122, -1.68449545, -33.68313521, ..., 97.61324629,
-71.12427809, 41.07406765]])
#计算每个个体的适应度值,就是上文所说的求出每个个体的函数值(两种方法)
#①利用省略缩写
fitness1 = np.array([f1(ind) for ind in population])
#②不省略
list_fitness = []
for ind in population :
list_fitness.append(f1(ind))
fitness2 = np.array(list_fitness)
#两种方法结果是一样的
#查看两种方法得出结果是否不同
fitness1==fitness2
array([ True, True, True, True, True, True, True, True, True,
True, True, True, True, True, True, True, True, True,
True, True, True, True, True, True, True, True, True,
True, True, True, True, True, True, True, True, True,
True, True, True, True, True, True, True, True, True,
True, True, True, True, True, True, True, True, True,
True, True, True, True, True, True, True, True, True,
True, True, True, True, True, True, True, True, True,
True, True, True, True, True, True, True, True, True,
True, True, True, True, True, True, True, True, True,
True, True, True, True, True, True, True, True, True,
True])
差分进化算法过程
#定义两个列表
best_fitness_history = [] #用来储存最佳适应度值
best_solution_history = [] #用来存储最优解
#两层循环
for generation in range(generations): #外层循环用来判断是否超出定义迭代次数
new_population = np.copy(population) #复制一份population,对复制的种群进行以后的操作
for i in range(population_size): #内层循环用来判断超出种群范围以及提取种群信息
indices = list(range(population_size)) #定义一个大小和种群规模一样的列表,用于下面操作数据提取
indices.remove(i) #indices依次移除某位置的数据,用于记录此时的数据
a,b,c = population[np.random.choice(indices,3,replace = False)] #随机选择三个种群中的个体
#变异操作
mutant = a + F * ( b - c ) #对选择的三个个体进行变异操作
#交叉操作
crossover = np.random.rand(dimension) < CR1 #随机生成一个实数小于个体维度数,判断该实数是否小于交叉因子
trial = np.where(crossover,mutant,population[i]) #np.where(condition,x,y) 当where内有三个参数时,第一个参数表示条件,当条件成立时where方法返回x,当条件不成立时where返回y
#选择操作
trial_fitness = f1(trial) #对上面生成的新个体进行适应的求值,然后放入一个新的列表中
if trial_fitness < fitness1[i]: #如果新计算的个体适应度比原本个体的适应度好,选择新的个体以及新的适应度替换之前旧的数据
new_population[i] = trial #对副本中的数据进行替换,不影响原本的数据
fitness1[i] = trial_fitness
population = new_population #将新生成的种群替换旧的种群
best_fitness = np.min(fitness1) #找到一代中适应度列表中最好的适应度
best_solution = population[np.argmin(fitness1)] #找出一代中最好适应度对应的个体
best_fitness_history.append(best_fitness) #将一代中最好的适应度储存
best_solution_history.append(best_solution) #将一代中最好的个体储存
# 输出每一代的最优解和最优适应度
# print(f"Generation {generation + 1}:\n Best Solution = {best_solution}, \nBest Fitness = {best_fitness}")
对计算出来的数据进行绘图
# 绘制适应度值随代数变化的曲线
plt.plot(best_fitness_history,c = 'blue',label = '迭代')
plt.legend(fontsize = 12) #标明每条线的详细信息
plt.title('F1')
plt.xlabel('迭代次数')
plt.ylabel('最佳适应度')
plt.grid(True)
plt.show()