粒子群算法(PSO)的python实现

1.背景

实际上网上关于pso算法的这个呢有很多,也不乏代码实现,包括matlab和python实现。但是查看各位大佬的代码,发现或多或少存在一些问题,下面就基于@大灰狼学编程的博客,对其代码进行部分纠正,希望大家多批评指正(ps:对于原理的讲解,我更推荐博客https://blog.csdn.net/m0_60307882/article/details/123864693)。

2.修改后的代码

# 使用粒子群算法计算: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()

更新于2022.11.13

再次手写了一遍,但这次增将其封装程度,将其写成了一个类,同时也方便了传参。

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——神采的二舅

你可能感兴趣的:(python,算法)