一、问题描述
现有适应度函数 f ( x ) = x ∗ s i n ( x ) ∗ c o s ( x ) − 2 ∗ s i n ( 3 ∗ x ) f(x) = x*sin(x)*cos(x) - 2*sin(3*x) f(x)=x∗sin(x)∗cos(x)−2∗sin(3∗x), 求 x ∈ ( 0 , 50 ) x\in(0, 50) x∈(0,50)的最小值。这就是典型的解空间搜索问题,如果确定了 x x x的精度为四位小数,自然可以遍历 [ 0.0001 , 49.9999 ] [0.0001, 49.9999] [0.0001,49.9999]来寻找最优解,但这显然不是值得推广的高效的算法。函数图像如图所示,最小值在A处取得
二、PSO算法求解的代码实现
-
导入必要的库
import matplotlib.pyplot as plt import numpy as np
-
定义适应度函数
def fun(x): f = x * np.sin(x) * np.cos(2 * x) - 2 * x * np.sin(3 * x) return f
-
初始化粒子群:
- 由 n = 20 n = 20 n=20 个粒子构成;
- 由于函数只有一个自变量,所以是 d = 1 d=1 d=1 一维空间;
- 设置总共迭代次数为 g e r = 100 ger=100 ger=100次;
- 自变量的取值范围 x _ l i m i t ∈ [ 0 , 50 ] x\_{limit}\in[0, 50] x_limit∈[0,50] ;
- 速度太大的话会导致粒子移动的距离太远,设置速度限制为 v _ l i m i t ∈ [ − 10 , 10 ] v\_{limit} \in[-10, 10] v_limit∈[−10,10];
- w 、 c 1 、 c 2 w、c_1、c_2 w、c1、c2 是权重值;
- 最后使用随机函数生成初态粒子 x x x 以及每个粒子的速度 v v v 。
N = 20 # 种群粒子数 d = 1 # 解空间维数 ger = 100 # 迭代次数 x_limit = [0, 50] # 自变量的取值范围 v_limit = [-10, 10] # 速度限制 w = 0.8 # 自身速度的惯性权重 c1 = 0.5 # 朝自身搜索最优点的学习因子 c2 = 0.5 # 朝群体搜索最优点的学习因子 x = np.random.uniform(0, 50, size=N) # 初始化种群位置 v = np.random.rand(N) # 初始话种群速度
-
设置必要的记录型变量
- 用 x m xm xm 记录每个个体自身的历史最佳位置
- 用 f x m fxm fxm 记录个体最佳为值对应的适应度,初始为无穷大
- 用 y m ym ym 记录整个种群的最佳位置
- 用 f y m fym fym 记录整个种群的最佳适应度,初始为无穷大
xm = x # 记录每个个体的历史最佳位置 ym = np.zeros(d) # 记录种群的最佳位置 d维的 fxm = np.ones(N) * np.inf # 记录每个个体的最佳适应度 fym = np.inf # 记录种群的最佳适应度
这里的变量是用来做记录;
通过个体最佳适应度 f x m fxm fxm 判断是否需要更新个体最佳位置 x m xm xm,;
通过种群最佳适应度 f y m fym fym, 判断是否需要更新种群最佳位置 y m ym ym;
最终: 通过个体最佳位置 x m xm xm 和种群最佳位置 y m ym ym 来不断更新速度矢量。
-
迭代寻找最优解
- 将粒子的位置 x x x,传入适应度函数 f y n ( x ) fyn(x) fyn(x),获取当前所有粒子的适应度 f x fx fx;
- 遍历所有的适应度用两个if语句:更新个体最佳适应度 f x m fxm fxm,以及个对应的位置 x m xm xm; 更新整个种群的最佳适应度 f y m fym fym, 以及对应的位置 y m ym ym;
- 根据 x m , y m xm, ym xm,ym,依据理论篇中的公式更新速度 v v v,再更新位置 x x x后进行下一轮迭代;
- g e r = 100 ger=100 ger=100次迭代后, f y m fym fym 保存了种群最佳适应度, y m ym ym保存了最佳适应度的位置
iter = 1 # 第一代 while iter <= ger: iter += 1 fx = fun(x) # 计算每个个体当前位置的的适应度 for i in range(N): if fx[i] < fxm[i]: # 判断是否需要更新个体最佳适应度和最佳位置 fxm[i] = fx[i] # 更新每个个体的最佳适应度 xm[i] = x[i] # 更新每个个体的最佳位置 if fx[i] < fym: # 判断是否需要更新群体最佳适应度和最佳位置 fym = fx[i] # 更新最佳适应度 ym = xm[i] # 更新最佳适应度的位置 v = v * w + \ c1 * np.random.random() * (xm - x) + \ c2 * np.random.random() * (np.tile(ym, 20) - x) # 更新速度 # 速度修正,不超过规定的速度范围 v = np.where(v > v_limit[1], v_limit[1], v) v = np.where(v < v_limit[0], v_limit[0], v) x = x + v # 更新位置 # 位置修正,不超过取值范围 x = np.where(x > x_limit[1], x_limit[1], x) x = np.where(x < x_limit[0], x_limit[0], x) # 输出最后结果 print("最佳适应度为:", fym) print("最佳适应度的点为:", ym)
三、算法补充
- 算法优点:思维简单易懂,比较容易实现
- 算法缺点:容易出现局部