实际上网上关于pso算法的这个呢有很多,也不乏代码实现,包括matlab和python实现。但是查看各位大佬的代码,发现或多或少存在一些问题,下面就基于@大灰狼学编程的博客,对其代码进行部分纠正,希望大家多批评指正(ps:对于原理的讲解,我更推荐博客https://blog.csdn.net/m0_60307882/article/details/123864693)。
# 使用粒子群算法计算:f(x)=x^2+y^2+x的最小值
import numpy as np
X = np.arange(-5, 5, 0.1)
Y = np.arange(-5, 5, 0.1)
X, Y = np.meshgrid(X, Y)
Z = X ** 2 + Y ** 2 + X
def fitness_func(X):
"""适应度,也就是函数的值"""
x = X[:, 0]
y = X[:, 1]
return x ** 2 + y ** 2 + x
#更新速度,根据公式V(t+1)=w*V(t)+c1*r1*(pbest_i-xi)+c2*r2*(gbest_xi)
def v_update(V, X, c1, c2, pbest, gbest, w, max_val):
"""
Parameters
----------
V:公式中的V(t),t时刻的粒子的速度(这里好像是批处理)
X:批样本的t时刻的位置
c1:惯性系数
c2:惯性系数
pbest:单个粒子i历史最优位置
gbest:群体粒子的历史最优位置
w:惯性系数
max_val:防止速度过大而设定的最大值
Returns
-------
更新后的速度V
"""
size = X.shape[0] # 样本个数
r1 = np.random.random((size, 1))
r2 = np.random.random((size, 1))
V_ = w * V + c1 * r1 * (pbest - X) + c2 * r2 * (gbest - X)
V_[V_ < -max_val] = -max_val
V_[V_ > max_val] = max_val
return V_
def p_update(X, V):
"""更新粒子位置"""
return X + V
def pso():
"""粒子群算法主函数"""
w = 1
c1 = 2
c2 = 2
r1 = None
r2 = None
dim = 2
size = 20 # 使用20个粒子
iter_num = 1000 # 最大迭代次数
max_val = 0.5
best_fitness = float(9e10)
fitness_val_list_group = [] # 存放每次的全局最优位置
# 初始化各个粒子的位置
X = np.random.uniform(-5, 5, size=(size, dim))
# 初始化各个粒子的初试速度
V = np.random.uniform(-0.5, 0.5, size=(size, dim))
p_fitness = fitness_func(X) # 初始化个体适应度
g_fitness = p_fitness.min() # 初始化集体适应度
fitness_val_list_group.append(g_fitness) # 初始化群体最优位置列表
pbest = X # 初始化个体最优位置,每行对应一个个体的最优位置
gbest = X[p_fitness.argmin()] # 初始化种群最优位置,为标量
# 迭代
for i in range(1, iter_num):
# 更新粒子位置与速度
V = v_update(V, X, c1, c2, pbest, gbest, w, max_val=max_val)
X = p_update(X, V)
p_fitness2 = fitness_func(X) # 更新后的粒子的适应度,针对这一次中的所有群体
g_fitness2 = p_fitness2.min() # 更新后的种群的最佳适应度,针对这一次中的所有群体
# 现在需要与之前所有迭代中的个体最优位置和群体最优位置作对比,对二者进行更新
# 这里直接与上一次的结果进行比较即可:
for j in range(size): # 对每个样本做遍历
if p_fitness[j] > p_fitness2[j]:
pbest[j] = X[j] # 更新各个个体的最优位置,所有次数
p_fitness[j] = p_fitness2[j] # 各个个体的最优位置更新了,其对应的适应度也要跟上
if g_fitness > g_fitness2:
gbest = X[p_fitness2.argmin()] # 更新后的群体最优点,所有次数
g_fitness = g_fitness2 # 对应的适应度跟上
# 记录最佳迭代记录
fitness_val_list_group.append(g_fitness)
# 输出迭代结果
print("最优值是:%.5f" % fitness_val_list_group[-1])
print("最优解是:x=%.5f,y=%.5f" % (gbest[0], gbest[1]))
pso()
再次手写了一遍,但这次增将其封装程度,将其写成了一个类,同时也方便了传参。
import numpy as np
class PSO:
def __init__(self,target_func,size=40,w=1,c1=2,c2=2,max_v=0.5,dim=2,max_iter=1000):
"""
求目标函数最小值的粒子群算法,参数如下
target:目标函数
size:粒子群的个数
w:惯性系数
c1,c2:权重系数
max_v:最大速度
dim:粒子所运动的维度空间,即自变量的个数
max_iter:最大迭代次数
"""
self.size=size
self.w=w
self.c1=c1
self.c2=c2
self.max_v=max_v
self.dim=dim
self.max_iter=max_iter
self.positions=np.random.uniform(-5,5,size=(size,dim)) # 随机初始化粒子的位置
self.v=np.random.uniform(-0.5,0.5,size=(size,dim))
self.func=target_func
def v_update(self,p_best,g_best):
r1=np.random.random((self.size,1))
r2=np.random.random((self.size,1))
self.v=self.w*self.v+self.c1*r1*(p_best-self.positions)+self.c2*r2*(g_best-self.positions)
# 限制速度
self.v=np.clip(self.v,-self.max_v,self.max_v)
# return self.v
def p_update(self,):
self.positions+=self.v
self.positions=np.clip(self.positions,-5,5)
# return self.positions
# 让我们的粒子群开始摇滚吧!!
def roll(self,):
"""开始迭代"""
best_fitness=float(9e10)
fitness_val_list_group=[]
p_fitness=self.func(self.positions) # 初始化个体适应度
g_fitness=p_fitness.min() # 初始化集体适应度
fitness_val_list_group.append(g_fitness)
p_best=self.positions # 初始化个体的初始位置
g_best=self.positions[p_fitness.argmin()] # 初始化种群最优位置
# iter...let's roll out!
for i in range(self.max_iter):
self.v_update(p_best,g_best,)
self.p_update()
p_fitness2=self.func(self.positions)
g_fitness2=p_fitness2.min()
# 更新每个粒子的历史最优位置和历史最优适应度
for j in range(self.size):
if p_fitness2[j]<p_fitness[j]:
p_best[j]=self.positions[j]
p_fitness[j]=p_fitness2[j]
# # 更新群体的全局历史最优位置和全局历史最优适应度
if g_fitness2<g_fitness:
g_fitness=g_fitness2
g_best=self.positions[p_fitness2.argmin()]
fitness_val_list_group.append(g_fitness)
print("最优val是: %.5f"%(fitness_val_list_group[-1]))
print("最优解是:x=%.5f,y=%.5f" % (g_best[0], g_best[1]))
by——神采的二舅