免疫算法
- 免疫算法的原理和遗传算法有点像,其中免疫算法的免疫操作的选择、变异操作和遗传算法是同一个策略。
- …原理部分的公式有点多,这个算法的理论有点乱,以后再来整理。本次主要关注的是代码实战。
免疫算法生物学概念对照表
免疫算法流程图
- 这个算法和遗传算法很像,但又有本质的区别。而且步骤比较复杂,感觉不好用。
Python代码
f ( x ) = ∑ i = 1 n x i 2 ( − 20 ⩽ x i ⩽ 20 ) \large f(x)=\sum_{i=1}^{n} x_{i}^{2}\left(-20 \leqslant x_{i} \leqslant 20\right) f(x)=i=1∑nxi2(−20⩽xi⩽20)
import numpy as np
import matplotlib.pyplot as plt
import matplotlib
from numpy import random
class IA: # immune algorithm
def __init__(self,NP,D,Xs,Xx,G,E,Pm,alfa,belta,st,NC,deta0):
'''
:param NP: 种群数量
:param D: 维度
:param Xs: 上限
:param Xx: 下限
:param G: 迭代次数
:param E: 适应度误差阈值
:param Pm: 变异概率
:param alfa: 激励度适应度权重
:param belta: 激励度浓度权重
:param st: 解的相似度阈值
:param NC: 克隆个数
:param deta0: 随机扰动、邻域系数初值
'''
self.D = D
self.NP = NP
self.Xs = Xs
self.Xx = Xx
self.G = G
self.E = E
self.Pm = Pm
self.alfa = alfa
self.belta = belta
self.st = st
self.NC = NC
self.deta0 = deta0
def func(self,x):
return sum(x**2)
def mutation(self,data,a,b,g): # mutation突变、变异
# 变异操作
deta = self.deta0/(g+1) # 扰动:邻域系数
r = []
for i in range(a * b):
r.append(True if np.random.rand() < self.Pm else False) # 产生变异次数
r = np.array(r)
r = r.reshape(a, b)
p = []
for i in range(np.sum(r == True)):
# p.append(np.random.rand() * (self.Xs - self.Xx) + self.Xx)
p.append((random.rand()-0.5)*deta)
p = np.array(p) # 根据变异次数重新生成新解
k = data[r]
data[r] = p + k
return data
def boundary(self,u): # boundary边界
# 边界条件处理
a = sum(u[u<self.Xx])# 下限
b = sum(u[u>self.Xs]) #上限
k = a + b
while k > 0:
if a > 0:
u[u < self.Xx] = random.rand() * (self.Xs - self.Xx) + self.Xx
elif b > 0:
u[u > self.Xs] = random.rand() * (self.Xs - self.Xx) + self.Xx
a = sum(u[u < self.Xx]) # 下限
b = sum(u[u > self.Xs]) # 上限
k = a + b
return u
def c_incentive(self,x,y,number):
# 计算个体浓度和激励度
ED = [] # Euclidean distance:欧式距离
dense = [] # 浓度
for n in range(number):
for j in range(number): # 解空间的每一个解与其他解(包括自身)的相似度
ed = sum((x[n] - x[j])**2)
if ed < self.st:
ed = 1
else:
ed = 0
ED.append(ed)
ds = sum(ED)/number # 解n的浓度
dense.append(ds)
# incentive:激励
dense = np.array(dense)
incentive = self.alfa*y - self.belta*dense
return incentive
def drawer(self):
y,x = self.immune()
plt.rc('legend', fontsize=16)
matplotlib.rcParams['font.family'] = 'Kaiti'
fig = plt.figure(figsize=(10, 5.5), dpi=100)
plt.plot(y, 'b:d', markerfacecolor='red', markersize=3, linewidth=1.5,
label='免疫算法仿真实例') # 1.线型颜色、线型风格、标记风格;2.线宽 3.标记颜色填充
plt.xlabel('迭代次数', fontproperties='Kaiti', fontsize=14) # 坐标轴标签设置
plt.ylabel('适应度函数值', fontproperties='Kaiti', fontsize=14)
plt.legend() # 添加图例
# 图题
plt.title(r'免疫算法求解$Min:f(x)=\sum_{i=1}^{n} x_{i}^{2}\left(-20 \leqslant x_{i} \leqslant 20\right)$',
fontproperties='Kaiti', fontsize=14)
plt.annotate('(最小值为:%.4f)' % y[-1], xy=(len(y), y[-1]), xytext=(len(y)-50, 70), fontproperties='Kaiti', fontsize=14,
arrowprops=dict(facecolor='red', shrink=1.5, width=1.5, headwidth=5))
plt.grid(True) # 网格
plt.show()
def immune(self):
# 初始化种群
x = random.rand(self.NP, self.D) * (self.Xs - self.Xx) + self.Xx
y = self.func(x.T)
y = np.array(y)
# 计算个体浓度和激励度
incentive_y = self.c_incentive(x,y,self.NP)
# 激励度按升序排列
k = np.argsort(incentive_y)
x = x[k] # 解空间重排
# 免疫循环
'''nnx:克隆变异种群'''
trace = []
for g in range(self.G):
by_nnx = []
bx_nnx = []
for i in range(int(self.NP/2)): # 选择前NP/2个解进行免疫操作
x0 = x[i] # 被选到的前NP/2的第i个解
nnx = np.tile(x0,(self.NC,1)) # 复制self.NC次
# 变异操作
nnx = self.mutation(nnx,self.NC,self.D,g)
# 边界条件处理
nnx = self.boundary(nnx)
nnx[1] = x[i] # 变异种群nnx:源操作数据 + (self.NC-1)个变异解
# 克隆抑制,保留适应度最好的解
y_nnx = self.func(nnx.T)
yk_nnx = np.sort(y_nnx) # 克隆变异种适应度排序
by_nnx.append(yk_nnx[0]) # 克隆变异种最优适应度
k = np.argsort(y_nnx)
xk_nnx = nnx[k]
bx_nnx.append(xk_nnx[0]) # 克隆变异种最优解 --》bx_nnx免疫种群
# 免疫种群激励度
bx_nnx = np.array(bx_nnx)
by_nnx = np.array(by_nnx)
incentive_nnx = self.c_incentive(bx_nnx,by_nnx,int(self.NP/2))
# 种群刷新
'''nx:新生种群'''
nx = random.rand(int(self.NP/2),self.D) * (self.Xs - self.Xx) + self.Xx
y_nx = self.func(nx.T)
# 新生种群激励度
incentive_nx = self.c_incentive(nx,y_nx,int(self.NP/2))
# 免疫种群与新生种群合并
sx = np.concatenate((bx_nnx,nx))
scy = np.concatenate((incentive_nnx,incentive_nx))
k = np.argsort(scy)
x = sx[k]
trace.append(self.func(x[0].T)) # 记录一次迭代最优适应度
if trace[-1]<self.E:
break
return trace,x
ia = IA(100,10,20,-20,500,0.001,0.7,1,1,0.2,10,-20)
y,x = ia.immune()
ia.drawer()
print(x[0])
print(y[-1])
print(len(y))
实验结果分析
- 效果和遗传算法差不多。