本文代码是对这篇文章代码的一个优化:
粒子群优化算法(PSO)python实践_python粒子群优化算法_MSTIFIY的博客-优快云博客
直接上代码:
import numpy as np
import random
import matplotlib.pyplot as plt
import time
import copy
def Fitness(x): # 适应度函数
fitness_value = x[0] * np.exp(x[1]) + x[2] * np.sin(x[1]) + x[3] * x[4] * x[5]
return fitness_value
class PSO(object):
def __init__(self, Dim, Num_Particle, Max_iter, p_low, p_up, v_low, v_high, w = 1., c1 = 2., c2 = 2.):
self.w = w # 惯性权值
self.c1 = c1 # 个体学习因子
self.c2 = c2 # 群体学习因子
self.D = Dim # 粒子维度
self.N = Num_Particle # 粒子群规模,初始化种群个数 100
self.Max_iter = Max_iter # 最大迭代次数 50
self.p_range = [p_low, p_up] # 粒子位置的约束范围
self.v_range = [v_low, v_high] # 粒子速度的约束范围
self.x = np.zeros((self.N, self.D)) # 粒子群的位置
self.v = np.zeros((self.N, self.D)) # 粒子群的速度
self.p_best = np.zeros((self.N, self.D)) # 每个粒子的最优位置
self.g_best = np.zeros((1, self.D))[0] # 种群(全局)的最优位置
self.p_bestFit = np.zeros(self.N) # 每个粒子的最优适应值
self.g_bestFit = float('Inf') # 初始的全局最优适应度
# 初始化所有个体和全局信息
for i in range(self.N):
for j in range(self.D):
self.x[i][j] = random.uniform(self.p_range[0][j], self.p_range[1][j])
self.v[i][j] = random.uniform(self.v_range[0], self.v_range[1])
self.p_best[i] = self.x[i] # 保存个体历史最优位置,初始默认第0代为最优
fit = Fitness(self.p_best[i])
self.p_bestFit[i] = fit # 保存个体历史最优适应值
if fit < self.g_bestFit: # 寻找并保存全局最优位置和适应值
self.g_best = self.p_best[i]
self.g_bestFit = fit
def interate(self, draw = 1):
best_fit = [] # 记录每轮迭代的最佳适应度,用于绘图
w_range = None
if isinstance(self.w, tuple):
w_range = self.w[1] - self.w[0]
self.w = self.w[1]
time_start = time.time() # 记录迭代寻优开始时间
for i in range(self.Max_iter):
self.update() # 更新主要参数和信息
if w_range:
self.w -= w_range / self.Max_iter # 惯性权重线性递减
print("\rIter: {:d}/{:d} fitness: {:.4f} ".format(i, self.Max_iter, self.g_bestFit, end = '\n'))
best_fit.append(self.g_bestFit.copy())
time_end = time.time() # 记录迭代寻优结束时间
print(f'Algorithm takes {time_end - time_start} seconds') # 打印算法总运行时间,单位为秒/s
if draw:
plt.figure()
plt.plot([i for i in range(self.Max_iter)], best_fit)
plt.xlabel("iter")
plt.ylabel("fitness")
plt.title("Iter process")
plt.show()
def update(self):
for i in range(self.N):
# 更新速度
self.v[i] = self.w * self.v[i] + self.c1 * random.uniform(0, 1) * (
self.p_best[i] - self.x[i]) + self.c2 * random.uniform(0, 1) * (self.g_best - self.x[i])
# 速度限制
for j in range(self.D):
if self.v[i][j] < self.v_range[0]:
self.v[i][j] = self.v_range[0]
if self.v[i][j] > self.v_range[1]:
self.v[i][j] = self.v_range[1]
# 更新位置
self.x[i] = self.x[i] + self.v[i]
# 位置限制
for j in range(self.D):
if self.x[i][j] < self.p_range[0][j]:
self.x[i][j] = self.p_range[0][j]
if self.x[i][j] > self.p_range[1][j]:
self.x[i][j] = self.p_range[1][j]
# 更新个体和全局历史最优位置及适应值
_fit = Fitness(self.x[i])
if _fit < self.p_bestFit[i]:
self.p_best[i] = copy.copy(self.x[i])
self.p_bestFit[i] = _fit
if _fit < self.g_bestFit:
self.g_best = copy.copy(self.x[i])
self.g_bestFit = _fit
if __name__ == '__main__':
low = [1, 1, 1, 1, 1, 1]
up = [25, 25, 25, 25, 25, 25] # Dim 等于要寻优参数的维度
pso = PSO(Dim=6, Num_Particle=100, Max_iter=50, p_low=low, p_up=up,
v_low=-1, v_high=1, w = 0.9, c1 = 2., c2 = 2.) # 初始化
pso.interate(draw = 1) # 迭代开始, draw = 1表示绘图
主要修改的地方在于:
'''
修改前
'''
_fit = self.fitness(self.x[i])
if _fit < self.p_bestFit[i]:
self.p_best[i] = self.x[i]
self.p_bestFit[i] = _fit
if _fit < self.g_bestFit:
self.g_best = self.x[i]
self.g_bestFit = _fit
'''
修改后
'''
_fit = Fitness(self.x[i])
if _fit < self.p_bestFit[i]:
self.p_best[i] = copy.copy(self.x[i])
self.p_bestFit[i] = _fit
if _fit < self.g_bestFit:
self.g_best = copy.copy(self.x[i])
self.g_bestFit = _fit
self.g_best = self.x[i]
这样的赋值语句中,获取的是 self.x[i]
的引用。在原始代码中,只要判断语句 if _fit < self.g_bestFit 成立一次, self.g_best 的值就一直等于变量 self.x[i]的值,即self.g_best保存的不是全局最优解。
在Python中,可以使用copy
模块来进行对象的复制。具体来说,因为self.x[i]
是可变对象(如列表),可以使用copy.copy
进行浅复制,如果是不可变对象(如数字、字符串等),可以使用copy.deepcopy
进行深复制。