粒子群算法(PSO)Python语言实现
文章目录
- 粒子群算法(PSO)Python语言实现
- 一、什么是粒子群算法
- 二、算法的实例讲解
- 1.实例引入
- 2.更新规则
- 3.实例对照
- 4.代码实现
- 5.运行结果
- 三、算法原理
- 总结
提示:以下是本篇文章正文内容,下面案例可供参考
一、什么是粒子群算法
PSO模拟的是鸟群的捕食行为。设想这样一个场景:一群鸟在随机搜索食物。在这个区域里只有一块食物。所有的鸟都不知道食物在那里。但是他们知道当前的位置离食物还有多远。那么找到食物的最优策略是什么呢。最简单有效的就是搜寻目前离食物最近的鸟的周围区域。
鸟群在整个搜寻的过程中,通过相互传递各自的信息,让其他的鸟知道自己的位置,通过这样的协作,来判断自己找到的是不是最优解,同时也将最优解的信息传递给整个鸟群,最终,整个鸟群都能聚集在食物源周围,即找到了最优解。
PSO中,每个优化问题的解都是搜索空间中的一只鸟。我们称之为“粒子”。所有的粒子都有一个由被优化的函数决定的适应值(fitness value),每个粒子还有一个速度决定他们飞翔的方向和距离。然后粒子们就追随当前的最优粒子在解空间中搜索。
PSO 初始化为一群随机粒子(随机解)。然后通过迭代找到最优解。在每一次迭代中,粒子通过跟踪两个"极值"来更新自己。第一个就是粒子本身所找到的最优解,这个解叫做个体极值pBest。另一个极值是整个种群目前找到的最优解,这个极值是全局极值gBest。另外也可以不用整个种群而只是用其中一部分作为粒子的邻居,那么在所有邻居中的极值就是局部极值。
二、算法的实例讲解
1.实例引入
这里我们以一个实例结合粒子群算法的基本原理进行讲解,
用粒子群算法求解该函数的极大值,首先将该函数的每一个n纬解视为一只鸟(粒子),整个算法运行的过程中鸟的数量是固定的。接下来就是模拟鸟群觅食也就是对每只鸟的数据进行更新,更新的的时候参考粒子群算法(PSO)算法的规则。
2.更新规则
粒子群算法(PSO)的更新规则:
W:惯性系数
C1:自我学习因子
C2:全局学习因子(学习因子一般为0到1之间的定值,在算法运行之初定义)
P:某一只鸟的觅食时所经过的位置中的最优处,其中t是迭代次数,d是指搜索空间的纬度,i为第i只鸟
G:全局最优点,即数次迭代中所有鸟经过的点的最优点
X:鸟群当前的位置
两个r均为0到1之间的随机数
此处则是在上一式子得到下次迭代速度的基础上对位置进行更新
3.实例对照
在代码实现时将每一只鸟定义为一个对象,对象中的属性有:鸟当前的变量x,y,当前鸟经过位置中的最优解x,y,鸟当前在x,y方向的速度,下次更新时鸟在x,y方向的速度。定义全局变量全局最优x,y,定义全局变量鸟的数量为n,在初始时根据x,y的范围随机生成x,y的初始值。
设置当前鸟在x,y方向的运动速度均为-0.2到+0.2之间的随机数,置C1的值为0.8,C2的值为0.85(这里我是随机设置的),r1,r2在每一轮的运行中生成0到1之间的随机数,W也随机设为0.8。至此我们已经把所有的参数都定义出来了。
4.代码实现
属性部分
# 定义鸟的属性
class Bird:
nowX = 0 # 鸟当前的x
nowY = 0 # 鸟当前的y
privateBestX = 0 # 当前鸟经过路径中最优的x
privateBestY = 0 # 当前鸟经过路径中最优的y
nowXV = 0 # 鸟当前的x方向的速度
nowYV = 0 # 鸟当前的y方向的速度
nextXV = 0 # 下一步鸟在x方向的速度
nextYV = 0 # 下一步鸟在y方向的速度
def getNowX(self):
return self.nowX
def getNowY(self):
return self.nowY
def getPrivateBestX(self):
return self.privateBestX
def getPrivateBestY(self):
return self.privateBestY
def getNowXV(self):
return self.nowXV
def getNowYV(self):
return self.nowYV
def getNextXV(self):
return self.nextXV
def getNextYV(self):
return self.nextYV
def setNowX(self,nowX):
self.nowX=nowX
def setNowY(self,nowY):
self.nowY=nowY
def setPrivateBestX(self,privateBestX):
self.privateBestX=privateBestX
def setPrivateBestY(self,privateBestY):
self.privateBestY=privateBestY
def setNowXV(self,nowXV):
self.nowXV=nowXV
def setNowYV(self,nowYV):
self.nowYV=nowYV
def setNextXV(self,nextXV):
self.nextXV=nextXV
def setNextYV(self,nextYV):
self.nextYV=nextYV
功能部分
from Bird import Bird
from random import *
import math
import xlwt
#计算速度V(t+1)
def calculateV(nowV,privateBestXorY,globeBestXorY,nowXorY):
a=randint(1,100)
r1=a/100
b=randint(1,100)
r2=b/100
result=0.8*nowV+r1*0.8*(privateBestXorY-nowXorY)+r2*0.85*(globeBestXorY-nowXorY)
return result
#计算函数值
def calculateFunction(x,y):
result=math.sin(2*(x*x+y*y))/(x*x+y*y)
return result
#获取更新后的x或y
def getRenewXorY(nowXorY,nextXVorYV):
result=nowXorY+nextXVorYV
return result
#每轮更新信息都有20只鸟
n=20
counter=30#更新30次
globeBestX=0#全局最优的x
globeBestY=0#全局最优的y
list=[]#用于存放鸟群
list1=[]#用于数据更新时起辅助作用
road=[]#存放鸟群的运动结果变化情况
for i in range(n):
road.append([])#一共n只鸟所以有n个[]
# 函数x与y的取值均为-4到4保留三位小数
#生成鸟群并初始化信息,初始时局部最优也是第一个点
#生成随机数
bird=Bird();
a=randint(1, 8000)
nowX=(a-4000)/1000
# 初始化nowX
bird.setNowX(nowX)
#设置局部最优的x
bird.setPrivateBestX(nowX)
b = randint(1, 8000)
nowY=(b-4000)/1000
#初始化nowY
bird.setNowY(nowY)
#设置局部最优的y
#随机生成x和y的初始速度范围是-0.2到0.2
bird.setPrivateBestY(nowY)
vx = (randint(1, 400)-200)/2000
bird.setNowXV(vx)
vy = (randint(1, 400)-200)/2000
bird.setNowYV(vy)
list.append(bird)
#鸟群信息的初始化完成
#定义全局最优
globeBestX=list[0].nowX
globeBestY=list[0].nowY
#找出初始时的全局最优,
for i in range(n):
if calculateFunction(list[i].nowX,list[i].nowY)>calculateFunction(globeBestX,globeBestX):
globeBestX=list[i].nowX
globeBestY=list[i].nowY
#已找出初始时的全局最优
# for j in list:
# print(j.getNextXV())
# print(j.getNowY())
# print(j.getNowX())
# print(j.getNextYV())
# print(j.getPrivateBestX())
# print(j.getPrivateBestY())
# print(j.getNowXV())
# print(j.getNowYV())
#对鸟群信息进行更新
for w in range(counter):#从list中取出bird对象w每变化一次就是一轮
for i in range(n):
sub=list[i]
#先对x进行处理
#计算更新后的v
v=calculateV(sub.getNowXV(),sub.getPrivateBestX(),globeBestX,sub.getNowX())
#计算更新后的x
x=getRenewXorY(sub.getNowX(),v)
sub.nowX=x
#判断全局最优并赋值
if calculateFunction(sub.nowX, sub.nowY) > calculateFunction(globeBestX, globeBestX):
globeBestX = sub.nowX
#判断局部最优并赋值
if calculateFunction(sub.nowX, sub.nowY) > calculateFunction(sub.getPrivateBestX(), sub.getPrivateBestY()):
sub.setPrivateBestX(sub.nowX)
#对y进行更新,更新的方式与对x的操作一样
#计算更新后的v
v=calculateV(sub.getNowYV(),sub.getPrivateBestY(),globeBestY,sub.getNowY())
#计算更新后的x
y=getRenewXorY(sub.getNowY(),v)
sub.nowY=y
if calculateFunction(sub.nowX, sub.nowY) > calculateFunction(globeBestX, globeBestX):
globeBestY = sub.nowY
if calculateFunction(sub.nowX, sub.nowY) > calculateFunction(sub.getPrivateBestX(), sub.getPrivateBestY()):
sub.setPrivateBestY(sub.nowY)
#对x,y更新完成
#rec为当前鸟群运动的函数值(代入x和y之后的计算结果)
rec=calculateFunction(sub.nowX, sub.nowY)
#将结果存入road中,存入的是鸟当前运动变量x,y代入计算后的函数值
road[i].append(rec)
list1.append(sub)#将更新后的点存入list1中
list.clear()#本轮更新结束后清空list
for k in list1:#将list1中的鸟群赋值到list中
list.append(k)
list1.clear()#将list1清空,本轮运行结束
#运行结束,打印全局最优解的函数结果(函数的极大值)
print(calculateFunction(globeBestX,globeBestY))
#将鸟群的运动路径存入文档中,其中每一列表示一只鸟的函数值变化情况
book = xlwt.Workbook(encoding='utf-8', style_compression=0)
# # 在excel中创建一个sheet表单,名字为test,可重设值
sheet = book.add_sheet('test', cell_overwrite_ok=True)
# #将数据写入表单中
for k in range(len(road)):
for k1 in range(len(road[k])):
# # 第一个参数是行,第二个参数是列
sheet.write(k1,k,road[k][k1])
# #保存excel文件
savepath='D:/datatest.xls'#文件路径
book.save(savepath)
5.运行结果
从运行结果可以看出随机产生的鸟群分布在目标范围的各个位置,但在经过一定次数的迭代之后,鸟群都会逐步逼近最优解。
三、算法原理
以二维空间为例
鸟群在觅食过程中会记录下自己经过的最优位置,由于鸟群之间的信息共享,所有鸟已知的觅食位置中必然会有一个全局最优的觅食位置。当前鸟在向全局最优位置移动时会同时受到已知的全局最优和局部最优的影响,如图虚线部分就是鸟接下来的运动方向,由A指向B和A指向C的向量经过权重的调整后构成,由于已知的全局最优也在迭代中更新,因此所有的鸟最终都会逐步逼近目标的最优位置
总结
对于初学者来说动态优化算法可能难以理解,与此类似,比如遗传算法,模拟退火算法,灰狼算法等都可以将每一个求解的n纬自变量抽象成一个类,将优化的目标作为数据更新的参考标准。