每个优化问题的解都是搜索空间中的一只鸟。称之为“粒子(Particle)”。所有的粒子都有一个由被优化的函数决定的适应值,每个粒子还有一个速度决定他们飞翔的方向和距离。然后粒子们就追随当 前的最优粒子在解空间中搜索。 PSO 初始化为一群随机粒子。然后通过叠代找到最优解。在每一次叠代中,粒子通过跟踪两个"极值" 来更新自己。第一个就是粒子本身所找到的最优解。 这个解叫做个体极值pBest,另一个极值是整个种群目前找到的最优解,这个极值是全局极值gBest。另外, 也可以不用整个种群而只是用其中一部分的邻居。 n个粒子在d维的搜索空间中,每个粒子的位置按如下公式进行变化: 混合PSO算法的流程如下: 1) 初始化所有粒子; 2) 评价每个粒子的适应值; 3) 使用适应值对粒子进行选择; 4) 调整粒子的搜索位置,粒子从新的位置开始搜索; 5) 检查终止条件。如果达到最大迭代次数或者最好解停滞不再变化,就终止迭代;否则回到步骤2)。 PSO算法主要包括以下几个要点: (l)粒子以随机的方式在整个问题空间中流动并且可以对自己所处的环境 进行评价(计算适应度); (2)每个粒子均可以记忆自己到过的最好位置; (3)每个粒子可以感知邻近粒子己达到的最好位置; (4)在改变速度的时候同时考虑自己到过的最好位置和邻近粒子已达到最 好位置" PSO算法的实现步骤为: (l)初始化粒子群。设群体规模为m,在允许的范围内随机设置粒子的初始位置和速度; (2)评价每个粒子的适应值,即计算每个粒子的目标函数fitness,; (3)对所有的i《{l,2,,,m},比较fitness和pbest。如果fitness优于pbest,则令pbest=fitness,, ; (4)对所有的i《{l,2,,,m},比较声fitness和gbest,如果fitness优于gbest,则重新设置gbest的索引号g; (5)根据(3-4),(3-5)式调整每一个粒子的位置和速度; (6)检查终止条件"如果达到最大迭代次数 或者最好解停滞不再变化,就终止迭代;否则返回(2)。 例1,#本文的优化函数是x^2-4x+3,显然这个函数在x=2时取最小值-1
# coding: utf-8
import numpy as np
import random
import matplotlib.pyplot as plt
# ----------------------PSO参数设置---------------------------------
class PSO():
def __init__(self, pN, dim, max_iter):
self.w = 0.8
self.c1 = 2
self.c2 = 2
self.r1 = 0.6
self.r2 = 0.3
self.pN = pN # 粒子数量 初始种群
self.dim = dim # 搜索维度,一维
self.max_iter = max_iter # 迭代次数100次
self.X = np.zeros((self.pN, self.dim)) # 所有粒子的位置和速度,初始都为0
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**2-4*X+3
# ---------------------初始化种群----------------------------------
def init_Population(self):
for i in range(self.pN): #遍历30个粒子
for j in range(self.dim): #维度
self.X[i][j] = random.uniform(0, 1) #用于生成一个0到1的随机浮点数: 0 <= n < 1.0,初始30个例子值,这里可以设置变量取值范围
self.V[i][j] = random.uniform(0, 1) # 初始30个速度值
self.pbest[i] = self.X[i] #个体位置
tmp = self.function(self.X[i]) #计算30个个体代入函数的结果,
self.p_fit[i] = tmp #30个结果
#中间结果,更新最小值
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): # 更新gbest\pbest 30个粒子
temp = self.function(self.X[i]) # temp赋值
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=" ") #当前最优,所有粒子都集中了,所以不一定是X[0]
#print(self.pbest,end="***")
print(self.fit) # 输出最优值
return fitness
# ----------------------程序执行-----------------------
my_pso = PSO(pN=30, dim=1, max_iter=100)
my_pso.init_Population()
fitness = my_pso.iterator()
# -------------------画图--------------------
plt.figure(1)
plt.title("Figure1")
plt.xlabel("iterators", size=14)
plt.ylabel("fitness", size=14)
t = np.array([t for t in range(0, 100)])
fitness = np.array(fitness)
plt.plot(t, fitness, color='b', linewidth=3)
plt.show()
#注意pN是指初始种群,一般来说初始种群越大效果越好
#dim是优化的函数维度,常见的初等函数和初等复合函数都是1维
#max_iter是迭代次数
#本文的优化函数是x^2-4x+3,显然这个函数在x=2时取最小值-1
#注意pN是指初始种群,一般来说初始种群越大效果越好 #dim是优化的函数维度,常见的初等函数和初等复合函数都是1维 #max_iter是迭代次数 最后结果[1.99997631] -0.9999999999999636,x=2,取最小值-1 例2 粒子群初始位置和速度随机产生,然后按公式(1)(2)进行迭代,直至找到满意的解。 下面以一个简单的优化问题为例,实现粒子群优化算法。 问题:min Y = X1 ** 2 + X2 **2(X1 >= -10,X2 <= 10)
import numpy as np
import random as rd
# min y = X1 * X1 + X2 * X2
# X1 >= -10
# X2 <= 10
def update(location,speed,pBest,gBest): #更新粒子群的位置和速度
for i in range(len(location)):
for j in range(len(speed[0])):
speed[i][j] = 0.5 * speed[i][j] + 2.0 * rd.random() * (pBest[i][j] - location[i][j]) + 2.0 * rd.random() * (gBest[j] - location[i][j])
location[i][j] += speed[i][j]
if location[i][j] < -10:
location[i][j] = -10
if location[i][j] > 10:
location[i][j] = 10
def objFunction(X1,X2): #计算目标函数值
f = X1 ** 2 + X2 ** 2
return f
def assess(location,pBest,gBest): #更新粒子的历史最优与全局最优
for i in range(len(location)):
if objFunction(location[i][0],location[i][1]) < objFunction(pBest[i][0],pBest[i][1]):
pBest[i][0] = location[i][0]
pBest[i][1] = location[i][1]
for i in range(len(pBest)):
if objFunction(pBest[i][0],pBest[i][1]) < objFunction(gBest[0],gBest[1]):
gBest[0] = pBest[i][0]
gBest[1] = pBest[i][1]
def init(): #随机初始化5个粒子的位置和速度
location,speed= [],[]
for i in range(5):
X1 = rd.uniform(-10, 10)
X2 = rd.uniform(-10,10)
V1 = rd.uniform(-5,5)
V2 = rd.uniform(-5,5)
location.append([X1,X2])
speed.append([V1,V2])
return location,speed
if __name__ == '__main__':
location,speed = init()
pBest = location
min = float("inf")
gBest = [0,0]
iters = 10000 #迭代次数
for i in range(len(pBest)):
if objFunction(pBest[i][0],pBest[i][1]) < min :
min = objFunction(pBest[i][0],pBest[i][1])
gBest[0] = pBest[i][0]
gBest[1] = pBest[i][1]
for i in range(iters):
update(location, speed, pBest, gBest)
assess(location, pBest, gBest)
print("最优解:" + str(gBest))
print("目标函数最优值:" + str(objFunction(gBest[0],gBest[1])))
算法描述
粒子群算法思想来源于实际生活中鸟捕食的过程。假设在一个n维的空间中,有一群鸟(m只)在捕食,食物位于n维空间的某个点上,对于第i只鸟某一时刻来说,有两个向量描述,一个是鸟的位置向量,第二个是鸟的速度。假设鸟能够判断一个位置的好坏,所谓“好坏”,就是离食物更近了还是更远了。鸟在捕食的过程中会根据自己的经验以及鸟群中的其他鸟的位置决定自己的速度,根据当前的位置和速度,可以得到下一刻的位置,这样每只鸟通过向自己和鸟群学习不断的更新自己的速度位置,最终找到食物,或者离食物足够近的点。更新速度和位置的表达式如下。
其效果图见下面:
sko.PSO 工具包讲解
python语言
首先要下载这个工具包。
这个anaconda下载大家都会
参数详解
如代码:
pso = PSO(func=demo_func, dim=3, pop=40, max_iter=150, lb=[0, -1, 0.5], ub=[1, 1, 1], w=0.8, c1=0.5, c2=0.5)
参数 说明
func 类型function, 所要求得优化函数
dim 类型int,维数,即函数的参数数
pop 类型int,种群的大小,也就是粒子的数量。我们使用“pop”来与GA保持一致。默认40
max_iter 类型int,iter迭代的最大值 默认150
lb 类型列表,下限。每个参数的下限
ub 类型列表,上限。每个参数的上限
W 对应公式里的惯性权重,默认0.8
C1 学习因子1,默认0.5
C2 学习因子2,默认0.5
属性 说明
pbest_x array_like, shape is (pop,dim)历史上每个粒子的最佳位置
pbest_y array_like, shape is (pop,1)历史上最好的粒子图像
gbest_x array_like, shape is (1,dim)general best location for all particles in history
gbest_y float历史上所有粒子的最佳值
gbest_y_hist list每个迭代的gbest_y
算例:有限制的粒子群
来源于官方文档例子
第一步,定义问题
def demo_func(x):
x1, x2, x3 = x
return x1 ** 2 + (x2 - 0.05) ** 2 + x3 ** 2
第二步,做粒子群算法
from sko.PSO import PSO
pso = PSO(func=demo_func, dim=3, pop=40, max_iter=150, lb=[0, -1, 0.5], ub=[1, 1, 1], w=0.8, c1=0.5, c2=0.5)
pso.run()
print('best_x is ', pso.gbest_x, 'best_y is', pso.gbest_y)
结果:
可以发现x的值落在限制区间内。
第三步,画出结果
import matplotlib.pyplot as plt
plt.plot(pso.gbest_y_hist)
plt.show()
算例:无限制的粒子群
def demo_func(x):
x1, x2, x3 = x
return x1 ** 2 + (x2 - 0.05) ** 2 + x3 ** 2
# %% Do PSO
from sko.PSO import PSO
pso = PSO(func=demo_func, dim=3)
pso.run()
print('best_x is ', pso.gbest_x, 'best_y is', pso.gbest_y)
# %% Plot the result
import matplotlib.pyplot as plt
plt.plot(pso.gbest_y_hist)
plt.show()
结果:
可以发现x1的值无限接近0,x2无限接近0.05,x3的值无限接近0.
所谓优化,我的理解是对一个问题求出它足够好的解,即使这个解不是最优解。如题中解接近0而不是0。在现实生活中,这个解满足要求。
数据批量做粒子群优化
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# @Author: yudengwu
# @Date : 2020/8/18
def demo_func(x):
x1, x2, x3 = x
return x1 ** 2 + (x2 - 0.05) ** 2 + x3 ** 2
from sko.PSO import PSO
import numpy as np
import pandas as pd
data={'lb':[[0,-1,0.5],[1,1,1],[2,3,4]],'ub':[[1,1,1],[2,2,2],[4,5,6]]}
data=pd.DataFrame(data)
print(data.shape[0])
def pso(lb,ub):
pso = PSO(func=demo_func, dim=3, pop=40, max_iter=150, lb=lb, ub=ub, w=0.8, c1=0.5, c2=0.5)
pso.run()
print('best_x is ', pso.gbest_x, 'best_y is', pso.gbest_y)
for i in range(data.shape[0]):
pso(data['lb'][i], data['ub'][i])
结果
python 实现粒子群
这是一个简单算例,通过该算例简单感受下粒子群
求取 函数x + 16 * np.sin(5 * x) + 10 * np.cos(4 * x) 的最大值
import numpy as np
import matplotlib.pyplot as plt
# 粒子(鸟)
class particle:
def __init__(self):
self.pos = 0 # 粒子当前位置
self.speed = 0
self.pbest = 0 # 粒子历史最好位置
class PSO:
def __init__(self):
self.w = 0.5 # 惯性因子
self.c1 = 1 # 自我认知学习因子
self.c2 = 1 # 社会认知学习因子
self.gbest = 0 # 种群当前最好位置
self.N = 20 # 种群中粒子数量
self.POP = [] # 种群
self.iter_N = 100 # 迭代次数
# 适应度值计算函数
def fitness(self, x):
return x + 16 * np.sin(5 * x) + 10 * np.cos(4 * x)
# 找到全局最优解
def g_best(self, pop):
for bird in pop:
if bird.fitness > self.fitness(self.gbest):
self.gbest = bird.pos
# 初始化种群
def initPopulation(self, pop, N):
for i in range(N):
bird = particle()#初始化鸟
bird.pos = np.random.uniform(-10, 10)#均匀分布
bird.fitness = self.fitness(bird.pos)
bird.pbest = bird.fitness
pop.append(bird)
# 找到种群中的最优位置
self.g_best(pop)
# 更新速度和位置
def update(self, pop):
for bird in pop:
# 速度更新
speed = self.w * bird.speed + self.c1 * np.random.random() * (
bird.pbest - bird.pos) + self.c2 * np.random.random() * (
self.gbest - bird.pos)
# 位置更新
pos = bird.pos + speed
if -10 < pos < 10: # 必须在搜索空间内
bird.pos = pos
bird.speed = speed
# 更新适应度
bird.fitness = self.fitness(bird.pos)
# 是否需要更新本粒子历史最好位置
if bird.fitness > self.fitness(bird.pbest):
bird.pbest = bird.pos
# 最终执行
def implement(self):
# 初始化种群
self.initPopulation(self.POP, self.N)
# 迭代
for i in range(self.iter_N):
# 更新速度和位置
self.update(self.POP)
# 更新种群中最好位置
self.g_best(self.POP)
pso = PSO()
pso.implement()
best_x=0
best_y=0
for ind in pso.POP:
#print("x=", ind.pos, "f(x)=", ind.fitness)
if ind.fitness>best_y:
best_y=ind.fitness
best_x=ind.pos
print(best_y)
print(best_x)
x = np.linspace(-10, 10, 100000)
def fun(x):
return x + 16 * np.sin(5 * x) + 10 * np.cos(4 * x)
y=fun(x)
plt.plot(x, y)
plt.scatter(best_x,best_y,c='r',label='best point')
plt.legend()
plt.show()
参考网上众多python实例,总结记录