遗传算法
原理
遗传算法是一种仿生优化算法,其灵感源于生物进化和基因传的机制。通过模拟生物进化过程中的交叉、变异等操作,逐步优化一个问题的解,以实现最优解的搜索。在遗传算法中,每个解被编码成一个个体,交叉相当于两个个体基因交换,变则是在个体基础上进行随机修改。遗传算法的主要优点是可以处理多变量、多峰和非线性等问题,同时搜索范围较大。
简单来说,遗传算法是模拟自然选择和遗传机制的寻优方法。通过基因杂交,变异可能产生适应性强的后代,通过优胜劣汰的自然选择,适应能力强的基因结构就保存下来。一句话概括就是:优胜劣汰,胜者生存。
基本步骤:
1.初始化群:在优化问题的可行解空间中随机生成一个初始种群。
2.评价个体适应度:对于每个个体,计算其适应度,即问题目标函数的值。
3.选择操作:利用轮盘赌算法或其他选择策略,从当前种群中选择潜在优秀的个体,生成下一代种群。
4.基因操作:包括交叉和变异,对已选个体,在一定概率范围内进行基因的交叉、变异,并生成新的个体。
5.·替换操作:新生个体代替部分原来的个体,生成新的种群。
6.结束判断:根据预设的终止条件,判断是否满足结束条件,收敛或超过限制则结束,否则重复执行上述步骤。
代码示例
import numpy as np
a=-np.pi #变量下界
b=np.pi #变量上界
NP=100 #种群大小
NG=1000 #迭代次数
Pc=0.9 #交叉概率
Pm=0.1 #变异概率
eps=0.1 #离散精度,用于确定二进制码所需码长
def initial(length): # 生成二进制编码的初始种群,大小为(length, )
res=np.zeros(length)
for ii in range(length):
r = np.random.rand()
res[ii]=np.round(r)
return res
def fitness(x): # 计算函数的适应值
return np.sin(x)
def dec(a,b,x,L): # 将二进制编码的数值转换为实际数值
L2 = list(range(L-1,-1,-1))
Ji = []
for m in range(len(L2)):
Ji.append(x[m]*pow(2,L2[m]))
y1 = sum(Ji)
y = a + y1 * (b-a)/(pow(2,L)-1)
return y
L=int( np.ceil(np.log2((b - a)/eps+1))) # 根据离散精度,确定二进制编码需要的码长
x = np.zeros((NP,int(L))) # 当前种群的二进制编码矩阵
fx= np.zeros(NP) # 每个个体的适应值
nx = np.zeros((NP,int(L))) # 存储产生的新种群的矩阵,大小和x相同
PPx=np.zeros(NP,) # 种群的选择概率,与种群中个体的适应度成正比
rr2 = np.zeros(NP, ) # 存储产的随机数的数组,用于调试和测试
for i0 in range(NP):
x[i0,:]= initial(L) # 种群初始化
fx[i0] = fitness(dec(a,b,x[i0,:],L)) # 个体适应值
nx =x
for k in range(NG): # 遗传迭代主循环
sumfx = sum(fx) # 计算所有个体的适应值之和
Px= fx/sumfx # 计算每个个体的选择概率
PPx[0]=Px[0] # 计算选择概率的累加和于轮盘赌算法
for i2 in range(1,NP):
PPx[i2] = PPx[i2-1]+Px[i2]
for i in range(NP): # 对于每个种群个体,进行选择、交叉和变异操作
sita = np.random.rand() # 随机生成一个选择概率,根据轮盘赌算法获取一个父代个体
for n in range(NP):
if sita <= PPx[n]:
SelFather=n # 选择的父代个体的索引,根据轮盘赌算法随机抽取
break
Selmother = int((np.random.rand() * (NP - 1)))#选择的母代个体的索引,随机选择一个体
posCut = int((np.random.rand() * (L - 1)))#交叉点位置,随机选择两个个体进行交叉操作
r1 = np.random.rand() # 随机生成交叉和变异的随机数,存储到rr2中
rr2[i]=r1
if r1<=Pc: # 判断是否进行交叉操作
nx[i,1:posCut] = x[SelFather,1:posCut]
nx[i,(posCut+1):L] = x[Selmother,(posCut+1):L]
else:
nx[i, :] = x[SelFather, :] #进行交叉操作否则不进行交叉操作直接将父代个体的基因复制到下一代个体
r2 = np.random.rand()
if r2 <= Pm: # 在一定概率下进行变异操作
posMut = round(np.random.rand()*(L-1))# 变异点位置随机选择一个体进行变异操作
if nx[i,posMut]==1.0:
nx[i,posMut]=0.0
else:
nx[i, posMut] = 1.0
x = nx
for j in range(NP):
fx[j] = fitness(dec(a,b,x[j,:],L))
fv =float('-inf')
for i3 in range(NP):
fitx = fitness(dec(a, b, x[i3,:], L))
if fitx > fv:
fv = fitx
xv = dec(a, b, x[i3,:], L)
print(xv) #最优解和最优函数值
print(fv)
粒子群算法
概述
粒子群算法(Particle Swarm Optimization,简称PSO)是1995年Eberhart博士和Kennedy博士一起提出的一种基于群体协作的搜索算法,它通过模拟鸟群捕食行为来寻找最优解。
在粒子群算法中,每个优化问题的解都被视为搜索空间中的一个粒子。每个粒子都保存有自己的历史最优位置和全局最优位置,通过在搜索空间中追踪这些最优位置,粒子们可以找到最优解。
在算法的每一轮迭代中,每个粒子都会向全局最优位置和自身历史最优位置进行一定的“飞行动”,这个飞行由两部分组成:一部分是粒子对全局最优位置的追踪,另一部分是粒子对自身历史最优位置的追踪。
粒子群算法的特点是在于其群体协作性质。当一个粒子找到一个好的解时,它会通过“飞行动”将这个信息传递给其他粒子,帮助整个群体找到最优解。因此,粒子群算法是一种基于种群的随机优化技术,它具有快速、简单、全局搜索能力强的优点。同时,它也适用于解决复杂和非线性问题,被广泛应用于各种优化问题中。
一般步骤
1.初始化粒子群(速度和位置)、惯性因子、加速常数、最大迭代次数和算法终止的最小允许误差。
2.计算每个粒子的初始适应值。
3.找出个体和群体最优值和对应的位置。
4.根据公式更新每个粒子的速度和位置。
5.比较当前各粒子的适应值是否比历史局部最优值好,如果好,就更新粒子的局部最优值和对应位置。
6.找出当前粒子群众的全局最优值和对应的位置。
7.重复步骤4~6,直到满足设定的最小误差或达到最大迭代次数。
8.输出粒子群全局最优值和对应位置,以及各粒子的局部最优值和对应位置。
代码示例
import numpy as np
import random
import matplotlib.pyplot as plt
class PSO():
def __init__(self, pN, dim, max_iter):
self.w = 0.8 #衰减因子,用于减小粒子群的速度,防止超出搜索空间
self.c1 = 2 #c1, c2: 加速常数,控制速度的改变,用于调整粒子的方向
self.c2 = 2 #随子,用于随机调整粒子的方向
self.r1 = 0.6
self.r2 = 0.3
self.pN = pN #粒子群大小
self.dim = dim #解向量维度
self.max_iter = max_iter #最大迭代数
self.X = np.zeros((self.pN, self.dim)) #粒子的位置向量。
self.V = np.zeros((self.pN, self.dim)) #粒子的速度向量
self.pbest = np.zeros((self.pN, self.dim)) #粒子历史上最好的位置向量,即粒子在过去
经历过最优的位置
self.gbest = np.zeros((1, self.dim)) #群体最好的位置向量,即所有粒子历史上最
优的位置向量
self.p_fit = np.zeros(self.pN) #每个粒子的历史最优适应度
self.fit = 1e10 #群体历史最优适应度
def function(self, X):
return X ** 4 - 2 * X + 3
def init_Population(self): #用于初始化粒子群,并找到群体中历史最优粒子
for i in range(self.pN):
for j in range(self.dim):
self.X[i][j] = random.uniform(0, 1)
self.V[i][j] = random.uniform(0, 1)
self.pbest[i] = self.X[i]
tmp = self.function(self.X[i])
self.p_fit[i] = tmp
if tmp < self.fit:
self.fit = tmp
self.gbest = self.X[i]
def iterator(self): #每次迭代更新每个粒子的速度,并重新更新位置向量
fitness = []
for t in range(self.max_iter):
for i in range(self.pN):
temp = self.function(self.X[i])
if temp < self.p_fit[i]:
self.p_fit[i] = temp
self.pbest[i] = self.X[i]
if self.p_fit[i] < self.fit:
self.gbest = self.X[i]
self.fit = self.p_fit[i]
for i in range(self.pN):
self.V[i] = self.w * self.V[i] + self.c1 * self.r1 * (self.pbest[i] - self.X[i]) + \
self.c2 * self.r2 * (self.gbest - self.X[i])
self.X[i] = self.X[i] + self.V[i]
fitness.append(self.fit)
print(self.X[0], end=" ")
print(self.fit)
return fitness
my_pso = PSO(pN=30, dim=1, max_iter=100)
my_pso.init_Population()
fitness = my_pso.iterator()