申明!!本篇文章中所有的非代码性叙述和数学公式均摘录自差分进化算法(DE)详述
差分进化算法(Differential Evolution Algorithm,DE)是基于群体智能理论的优化算法,它是通过群体内个体间的合作与竞争而产生的智能优化算法,字面意思即可看出它有别于遗传算法的自由组合自然选择,它更侧重的是个体与个体和个体与自身间的关系,包括合作与竞争。
其主要步骤为:种群初始化,变异,交叉,适应度函数选择。
为实现差分进化算法全过程,本文主要目标为:求解[-3,3]区间内,
y
=
2
x
2
+
3
x
−
1
y=2x^2+3x-1
y=2x2+3x−1最小值所对应的x值。
1.初始化
- D为自变量维度,文章中D=1;
- NP种群规模总数即个体总数,文章中NP=100;
- 迭代次数100000;(由于种群中一次仅变异一个个体,所以迭代次数要多一些,可以设置种群中有若干个体均变异来降低迭代次数)
- 交叉概率0.1
- 确定自变量维度j的上下限,由于文章仅一个维度,因此j=1,上下限维度为-3,3;
- 初始化种群:每个个体总服从上下限之间的均匀分布加标准正态分布的随机偏差。
X i j , 0 = r a n f [ 0 , 1 ] ∗ ( X j ( U ) − X j ( L ) ) + X j ( L ) X_{ij,0}=ranf[0,1]*({X_{j}}^{(U)}-{X_{j}}^{(L)})+{X_{j}}^{(L)} Xij,0=ranf[0,1]∗(Xj(U)−Xj(L))+Xj(L)
其中i=1,2,3…,NP;j=1,2,3,…,D
#### 初始化 ####
NP = 100 # 种群个体数
D = 1 #自变量维度
iterate = 100000 #进化代数
x_l = -3 #上限
x_r = 3 #下限
CR = 0.1 # 交叉概率
#种群初始化:均分分布+标准正态分布的随机偏差
G = np.linspace(-3,3,100) + random.normalvariate(0,1)
2.变异
个体图片在进入下一代时,需要从种群中随机选择三个互不相同的个体进行变异。
v
i
,
G
+
1
=
X
r
1
,
G
+
F
∗
X
r
2
,
G
−
X
r
3
,
G
v_{i,G+1}=X_{r1,G}+F*{X_{r2,G}-X_{r3,G}}
vi,G+1=Xr1,G+F∗Xr2,G−Xr3,G
其中v为变异后个体(v_new),r1,r2,r3代表与其互不相同的个体,缩放因子为F,其范围为[0,2],即2*random.random()
index = random.sample(range(0,NP),4) # 随机选择的变异个体
v_new = G[index[1]] + 2*random.random()*(G[index[2]]-G[index[3]]) #变异
3.交叉
利用交叉概率来判断其是否进行基因间的交叉。由于交叉是针对每个维度的自变量参数,因此本文没有交叉这一步骤。本文想要尽可能地还原交叉过程,因此本文将一个维度进行交叉,省略判断条件j=rnbr(i)。
v
i
j
,
G
0
+
1
=
{
v
i
j
,
G
0
+
1
r
a
n
d
b
(
j
)
<
=
C
R
o
r
j
=
r
n
b
r
(
i
)
X
i
j
,
G
0
r
a
n
d
b
(
j
)
>
C
R
a
n
d
j
!
=
r
n
b
r
(
i
)
v_{ij,G_{0+1}}=\left\{ \begin{aligned} v_{ij,G_{0+1}} \quad randb(j)<=CR\;or \; j=rnbr(i) \\ X_{ij,G_{0}} \quad randb(j)>CR\; and \; j!=rnbr(i) \end{aligned} \right.
vij,G0+1={vij,G0+1randb(j)<=CRorj=rnbr(i)Xij,G0randb(j)>CRandj!=rnbr(i)
# G[index[0]] 为这一代发生变异的个体
if random.random() <= CR :
#多维度判断应该如下所示
#if random.random() <= CR or j == random.randint(0,D-1)
v_new = G[index[0]]+ 2*random.random()*(G[index[1]]-G[index[2]]) #变异
else:
v_new = G[index[0]]
4.边界值处理
因变异和交叉会导致新的个体的产生,所以有一些个体可能不满足约束,因此进行边界值处理。
(1)取上下限内的随机数来代替新变量
v_new = random.random()*(x_r - x_l) + x_l
(2)采用边界值吸收法处理
#边界值吸收法
if v_new <= x_l:
v_new = x_l
if v_new >= x_r:
v_new = x_r
5.适应度函数选择
这一代产生的新的个体v_new与上一代的个体进行比较,如果这一代更适用于环境(此处为适应度函数值更小)则将这一代的新个体替换原个体。
# objective function
def objective_value(x):
return 2*(x**2)+3*x-1
if objective_value(v_new) < objective_value(G[index[0]]):
G[index[0]] = v_new #新旧替换
综上所述,全部代码如下。
import numpy as np
import random
import math
#### 初始化 ####
NP = 100 # 种群个体数
iterate = 100000 #进化代数
x_l = -3
x_r = 3
CR = 0.1 # 交叉概率
# objective function
def objective_value(x):
return 2*(x**2)+3*x-1
# 初始化
G = np.linspace(-3,3,100) + random.normalvariate(0,1)
def Differential_Evolution(G):
# 变异(随机选择一个当前个体与其他三个个体进行变异)
index = random.sample(range(0,NP),4) # 随机选择的变异个体
# 2*random.random() 为 F 缩放因子
# 交叉
if random.random() <= CR :# j == random.randint(0,D-1)
v_new = G[index[1]] + 2*random.random()*(G[index[2]]-G[index[3]]) #变异
if v_new <= x_l :
# 任选其一
v_new = random.random()*(x_r - x_l) + x_l # 上下限之间取随机数来代替不在范围内的值
v_new = x_l # 边界值吸收法
if v_new >= x_r:
v_new = random.random()*(x_r - x_l) + x_l
v_new = x_r
else:
v_new = G[index[0]]
# 适应度函数
if objective_value(v_new) < objective_value(G[index[0]]):
G[index[0]] = v_new
for i in range(iterate):
Differential_Evolution(G)
print("final iterating is ",G)
补充一点:由于Differential_Evolution()函数中,只是选取这一代中的某一个个体变异,因此需要迭代10万次才能达到最小值结果。如果想要迭代次数降低则可以增加一次查分进化算法中种群中个体变异的个数,以达到迭代次数降低的目的。
通过如下的运行结果显示,最终稳定在-0.75附近,即找到了二维曲线在[-3,3]中的最小值所对应的横坐标即x=-0.75。