【数学建模学习笔记】启发式算法:粒子群算法

零基础小白看懂粒子群优化算法(PSO)

一、什么是粒子群优化算法?

简单说,粒子群优化算法(PSO)是一种模拟鸟群 / 鱼群觅食的智能算法。想象一群鸟在找食物:

  • 每只鸟(叫 “粒子”)不知道食物在哪,但能看到自己飞过的地方中 “最可能有食物” 的位置(个体经验);
  • 也能看到整个群体中 “最可能有食物” 的位置(群体经验);
  • 它们会根据这两个经验调整飞行方向和速度,慢慢靠近食物(最优解)。

PSO 就是用这种思路解决 “找最优解” 的问题,比如 “如何让某个函数的结果最小(或最大)”。

二、核心概念拆解

  1. 粒子:算法中的 “搜索者”,每个粒子有两个关键属性:

    • 位置:当前在搜索空间中的坐标(比如在三维空间中,位置可以用 (x1, x2, x3) 表示);
    • 速度:下一步移动的方向和快慢。
  2. 适应度函数:判断 “这个位置好不好” 的标准。比如我们想最小化函数f(x) = -10x1 - e^(-x2/10 - x3),那每个粒子的位置代入这个函数后,结果越小,说明位置越 “好”。

  3. 个体最优(p_best):每个粒子自己飞过的所有位置中,适应度最好的那个位置(“我之前飞过的地方里,这里最可能有食物”)。

  4. 全局最优(g_best):整个群体所有粒子飞过的位置中,适应度最好的那个位置(“大家飞过的地方里,这里最可能有食物”)。

  5. 位置和速度更新:粒子每次移动时,会根据以下规则调整速度和位置:

    • 速度 = 惯性(保持之前的速度) + 个体经验(向自己的 p_best 靠近) + 群体经验(向全局的 g_best 靠近);
    • 新位置 = 当前位置 + 新速度。

    就像鸟飞的时候,既不会完全忘记之前的方向(惯性),也会参考自己和同伴的最佳经验调整方向。

三、算法怎么跑起来?(用例子和代码说话)

假设我们要解决的问题是:最小化函数f(x) = -10x1 - e^(-x2/10 - x3),其中 x1 的范围是 0-1,x2 是 1-80,x3 是 0-120。

1. 初始化

先创建 100 个粒子(N=100),每个粒子有 3 个维度(x1, x2, x3,即 D=3);随机给每个粒子分配初始位置(在上述范围内)和初始速度(比如 - 1 到 1 之间)。

在代码中,初始化的实现如下:

# 导入必要的库
import numpy as np  # 用于数值计算
import random       # 用于生成随机数
import math         # 用于数学运算
import matplotlib.pyplot as plt  # 用于绘图# 2. 初始化粒子的位置和速度
def initialize_particles(num_particles, num_dimensions, pos_low, pos_high, vel_low, vel_high):"""参数说明:- num_particles:粒子数量- num_dimensions:变量维度(这里是3,因为有x1、x2、x3)- pos_low/pos_high:每个变量的位置范围(列表形式)- vel_low/vel_high:速度范围"""# 初始化位置矩阵(行数=粒子数,列数=维度)positions = np.zeros((num_particles, num_dimensions))# 初始化速度矩阵velocities = np.zeros((num_particles, num_dimensions))for i in range(num_particles):  # 遍历每个粒子for j in range(num_dimensions):  # 遍历每个维度(变量)# 位置在[pos_low[j], pos_high[j]]范围内随机生成positions[i][j] = random.uniform(pos_low[j], pos_high[j])# 速度在[vel_low, vel_high]范围内随机生成velocities[i][j] = random.uniform(vel_low, vel_high)return positions, velocities

2. 定义适应度函数

适应度函数是判断位置好坏的标准,对于我们要最小化的函数,代码定义如下:

# 1. 定义适应度函数(目标函数)
# 这里要最小化的函数:f(x) = -10*x1 - e^(-x2/10 - x3)
def fitness(x):# x是一个列表,包含3个变量:x[0]是x1,x[1]是x2,x[2]是x3x1, x2, x3 = x[0], x[1], x[2]return -10 * x1 - math.exp(-x2/10 - x3)  # 计算函数值

3. 找初始最优

计算每个粒子的适应度(代入函数算结果);每个粒子的初始 “个体最优” 就是自己的初始位置;从所有粒子中挑出适应度最小的位置,作为 “全局最优”。

这部分在主函数中初始化个体最优和全局最优时实现:

# 初始化个体最优:一开始每个粒子的最优位置就是自己的初始位置
p_best_pos = positions.copy()  # 个体最优位置矩阵
# 计算每个粒子的初始适应度(目标函数值)
p_best_val = np.array([fitness(pos) for pos in positions])  # 个体最优值数组# 初始化全局最优:从个体最优中找最好的
g_best_idx = np.argmin(p_best_val)  # 找到适应度最小的索引(因为我们要最小化函数)
g_best_pos = p_best_pos[g_best_idx].copy()  # 全局最优位置
g_best_val = p_best_val[g_best_idx]  # 全局最优值

4. 迭代优化(重复 100 次,即 M=100)

每个粒子根据 “惯性、个体最优、全局最优” 更新速度和位置;每次移动后,重新计算适应度,如果比自己之前的 “个体最优” 更好,就更新个体最优;再从所有个体最优中挑出最好的,更新全局最优。

速度和位置更新的代码实现:

# 3. 更新粒子的位置和速度
def update_particles(positions, velocities, p_best_pos, g_best_pos, w, c1, c2, pos_low, pos_high, vel_low, vel_high):"""参数说明:- p_best_pos:每个粒子的个体最优位置- g_best_pos:全局最优位置- w:惯性权重(控制对之前速度的保留程度)- c1、c2:学习因子(控制个体/群体经验的影响程度)"""num_particles, num_dimensions = positions.shape  # 获取粒子数和维度for i in range(num_particles):  # 遍历每个粒子for j in range(num_dimensions):  # 遍历每个维度# 生成0-1之间的随机数(增加搜索随机性)r1 = random.uniform(0, 1)r2 = random.uniform(0, 1)# 速度更新公式:惯性 + 个体经验 + 群体经验velocities[i][j] = (w * velocities[i][j]  # 惯性部分+ c1 * r1 * (p_best_pos[i][j] - positions[i][j])  # 向个体最优靠近+ c2 * r2 * (g_best_pos[j] - positions[i][j]))  # 向全局最优靠近# 限制速度在[vel_low, vel_high]范围内(避免速度过大)velocities[i][j] = max(min(velocities[i][j], vel_high), vel_low)# 位置更新公式:当前位置 + 新速度positions[i][j] += velocities[i][j]# 限制位置在[pos_low[j], pos_high[j]]范围内(避免超出变量定义域)positions[i][j] = max(min(positions[i][j], pos_high[j]), pos_low[j])return positions, velocities

5. 算法主函数

将上述步骤整合到主函数中,实现完整的 PSO 算法:

# 4. 粒子群优化算法主函数
def pso_algorithm(num_particles, num_dimensions, max_iter, pos_low, pos_high, vel_low, vel_high, w=0.9, c1=2, c2=2):"""参数说明:- max_iter:最大迭代次数(搜索多少次)- 其他参数同上"""# 初始化粒子位置和速度positions, velocities = initialize_particles(num_particles, num_dimensions, pos_low, pos_high, vel_low, vel_high)# 初始化个体最优:一开始每个粒子的最优位置就是自己的初始位置p_best_pos = positions.copy()  # 个体最优位置矩阵# 计算每个粒子的初始适应度(目标函数值)p_best_val = np.array([fitness(pos) for pos in positions])  # 个体最优值数组# 初始化全局最优:从个体最优中找最好的g_best_idx = np.argmin(p_best_val)  # 找到适应度最小的索引(因为我们要最小化函数)g_best_pos = p_best_pos[g_best_idx].copy()  # 全局最优位置g_best_val = p_best_val[g_best_idx]  # 全局最优值# 记录每次迭代的最优值(用于画图)best_values = [g_best_val]# 开始迭代搜索for iter in range(max_iter):# 更新粒子位置和速度positions, velocities = update_particles(positions, velocities, p_best_pos, g_best_pos, w, c1, c2, pos_low, pos_high, vel_low, vel_high)# 更新个体最优和全局最优for i in range(num_particles):current_val = fitness(positions[i])  # 当前位置的适应度# 如果当前位置比个体最优好(值更小),就更新个体最优if current_val < p_best_val[i]:p_best_pos[i] = positions[i].copy()p_best_val[i] = current_val# 从个体最优中找新的全局最优current_g_best_idx = np.argmin(p_best_val)current_g_best_val = p_best_val[current_g_best_idx]# 如果新的全局最优更好,就更新全局最优if current_g_best_val < g_best_val:g_best_pos = p_best_pos[current_g_best_idx].copy()g_best_val = current_g_best_val# 记录当前迭代的最优值best_values.append(g_best_val)# 打印迭代信息(每10次打印一次,避免输出太多)if (iter + 1) % 10 == 0:print(f"迭代第{iter+1}次,当前最优值:{g_best_val:.6f}")# 画收敛曲线(最优值随迭代次数的变化)plt.figure(figsize=(8, 5))plt.plot(best_values)plt.xlabel("迭代次数")plt.ylabel("最优目标函数值")plt.title("PSO算法收敛曲线")plt.grid(True)plt.show()return g_best_pos, g_best_val  # 返回最终找到的最优位置和最优值

6. 运行程序并查看结果

通过主程序调用 PSO 算法,设置参数并运行:

# 5. 主程序:运行PSO算法
if __name__ == "__main__":# 问题设置num_particles = 100  # 粒子数量(100个粒子一起搜索)num_dimensions = 3   # 变量维度(x1, x2, x3三个变量)max_iter = 100       # 最大迭代次数(搜索100次)# 变量范围:x1∈[0,1],x2∈[1,80],x3∈[0,120]pos_low = [0, 1, 0]pos_high = [1, 80, 120]# 速度范围(一般设为位置范围的10%-20%)vel_low = -1vel_high = 1# 运行PSO算法best_position, best_value = pso_algorithm(num_particles, num_dimensions, max_iter, pos_low, pos_high, vel_low, vel_high)# 输出结果print("\n优化结束!")print(f"找到的最优位置:x1={best_position[0]:.4f}, x2={best_position[1]:.4f}, x3={best_position[2]:.4f}")print(f"对应的最优目标函数值:{best_value:.6f}")

迭代结束后,全局最优位置就是算法找到的 “最佳解”。比如例子中最后得到的最佳位置可能是 (1, 1, 0),对应的函数结果约为 - 10.9048。

四、为什么要用 PSO?

  • 简单好懂:不需要复杂的数学推导,原理像 “群体找东西” 一样直观;
  • 灵活高效:能解决多变量、复杂函数的优化问题(比如最小化、最大化);
  • 容易实现:用 Python 等语言几行代码就能写出基本版本,如上述示例代码所示。

五、总结

粒子群优化算法(PSO)通过模拟群体中每个个体的 “学习”(参考自己和他人的经验)来搜索最优解,步骤简单、效果实用,是解决优化问题的常用工具。就像一群鸟通过互相 “借鉴” 飞行经验,最终找到食物最多的地方一样。

上述代码实现了粒子群优化算法,用于寻找目标函数f(x) = -10x1 - e^(-x2/10 - x3)的最小值(其中 x1、x2、x3 有明确的范围限制)。通过运行代码,可以直观看到粒子群算法如何通过群体协作逐步逼近最优解,适合零基础小白理解 PSO 的核心逻辑。如果想解决其他优化问题,只需修改 fitness 函数(目标函数)和 pos_low/pos_high(变量范围)即可。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/98469.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/98469.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Gitlab】Ubuntu 20.04服务器部署Gitlab

写一个 适用于 Ubuntu 20.04/22.04 的 GitLab 一键部署脚本&#xff0c;包括&#xff1a;安装依赖安装 GitLab CE配置公网 IP 或域名自动开启 HTTPS&#xff08;Let’s Encrypt&#xff09;配置防火墙下面是完整脚本&#xff1a;#!/bin/bash# # GitLab 一键安装脚本 # # 1. 检…

Android 15重磅升级:16KB内存页机制详解与适配指南

一、背景随着Android硬件架构的持续演进&#xff0c;新一代设备开始采用16KB内存页&#xff08;Page Size&#xff09;机制&#xff0c;逐步替代传统的4KB内存页设计。此项底层变更对应用兼容性产生直接影响&#xff0c;特别是对依赖Native层库、JNI接口或自定义内存管理模块的…

Mybatis-8 动态SQL

动态SQL-官方文档 文档地址 动态 SQL_MyBatis中文网 为什么需要动态SQL 1、动态SQL是MyBatis的强大特性之一 2、使用JDBC或其它类似的框架&#xff0c;根据不同条件拼接SQL语句非常麻烦&#xff0c;例如拼接时要确保不能忘记添加必要的空格&#xff0c;还要注意去掉列表最后一…

PySpark数据输入

PySpark数据输入 1.理解RDD对象 2.掌握PySpark数据输入的2种方法 RDD对象 PySpark支持多种数据的输入&#xff0c;在输入完成后&#xff0c;都会得到一个&#xff1a;RDD类的对象 RDD全称为&#xff1a;弹性分布式数据集&#xff08;Resilient Distributed Datasets&#xff09…

【系统架构设计(16)】软件架构设计二:软件架构风格:构建系统的设计模式与选择指南

文章目录一、核心思想二、数据流风格&#xff1a;以数据流动为核心的处理模式三、调用返回风格&#xff1a;基于程序调用的层次化组织四、独立构件风格&#xff1a;基于事件驱动的松耦合架构五、虚拟机风格&#xff1a;提供抽象执行环境的架构模式六、仓库风格&#xff1a;以数…

MySQL速记小册(1)

1【Q】&#xff1a;Mysql中的数据排序是怎么实现的&#xff1f;【A】&#xff1a;排序过程中如果字段有索引&#xff0c;则利用索引排序。反之使用文件排序。在文件排序中&#xff0c;如果数据量少则在内存中排序&#xff0c;使用单路排序或双路排序。如果数据量大则利于磁盘文…

20250904 10:45_排查10.1.3.35新QMS系统RMAN备份失败问题(优化脚本里的环境配置,增加了check_oracle_env 函数)

一、RMAN备份失败日志如下 [2025-09-04 04:00:01] 备份脚本启动 [2025-09-04 04:00:01] 开始 RMAN 备份 CDB: ORCLCDB Message file RMAN<lang>.msb not found Verify that ORACLE_HOME is set properly [2025-09-04 04:00:01] RMAN 备份失败! 二、原备份脚本存档…

Vue3源码reactivity响应式篇之EffectScope

概述 EffectScope是Vue3中一个响应式系统的辅助类&#xff0c;用于管理副作用&#xff08;effect&#xff09;的作用域。它可以帮助我们更好地组织和管理多个effect&#xff0c;便于一起停止或暂停以及恢复&#xff0c;避免了全局状态的污染和管理的复杂性。 每一个vue组件的实…

MySQL 日志全解析:Binlog/Redo/Undo 等 5 类关键日志的配置、作用与最佳实践

1 二进制日志&#xff08;Binlog&#xff09;&#xff1a;配置与核心作用 Binlog 是 MySQL 中跨存储引擎的核心日志&#xff0c;记录所有数据修改操作&#xff0c;主要用于主从复制、数据备份恢复与跨库迁移。 1.1 Binlog 核心操作 开启 Binlog 若需开启 Binlog&#xff0c;需在…

springboot 之 HTML与图片生成 (2)

前言 之前写了一篇html转图片的 文章&#xff0c;使用中文时会出现乱码情况&#xff0c;后来又从网上找了下信息&#xff0c;这篇主要介绍下另一个转换库。 依赖 <!-- 用于将html转图片--><dependency><groupId>gui.ava</groupId><artifactId>…

计算机组成原理:计算机的分类

&#x1f4cc;目录&#x1f5a5;️ 计算机组成原理&#xff1a;计算机的分类——从架构到应用的全景梳理一、按处理数据类型分类&#xff1a;从“数字”到“混合”的演进&#xff08;一&#xff09;数字计算机&#xff1a;离散数据的“精准管家”1. 核心原理2. 关键优势3. 典型…

数据结构——单向循环链表代码(补充)

在此前的文章中&#xff08;链接如下&#xff09;&#xff0c;只有单向链表的代码&#xff0c;接下来我们来写单向循环链表&#xff0c;并用其实现一个简单的学生信息链表https://blog.csdn.net/2301_80406299/article/details/151157051?spm1011.2415.3001.10575&sharefr…

【Python自动化】 21.2 Pandas 读取 Excel 时的 dtype 参数完全指南

一、dtype 参数概述 dtype 参数用于指定列的数据类型&#xff0c;在读取 Excel 时非常重要&#xff0c;可以&#xff1a; 提高内存效率避免自动类型推断错误确保数据一致性提升读取性能 二、基本用法 1. 基础语法 import pandas as pd# 指定列数据类型 df pd.read_excel(data.…

gtest全局套件的测试使用

gtest全局套件的测试使用 #include <iostream> #include "gtest/gtest.h" #include <unordered_map>class MyEnvironment: public testing::Environment {public:virtual void SetUp() override{std::cout<<"单元测试前的环境初始化&#xff…

【系统分析师】第7章-基础知识:软件工程(核心总结)

更多内容请见: 备考系统分析师-专栏介绍和目录 文章目录 一、软件工程的基本概念 1.1 定义与意义 1.2 软件工程的基本原则 1.3 核心定义与边界 1.4 四大核心原则 1.5 三大核心目标 二、软件生命周期 2.1 定义与阶段划分 2.2 软件生命周期模型 三、软件开发方法 3.1 结构化方法…

量化基金从小白到大师 - 金融数据获取大全:从免费API到Tick级数据实战指南

量化基金从小白到大师 - 金融数据获取大全&#xff1a;从免费API到Tick级数据实战指南 各位&#xff0c;今天咱们要啃一块硬骨头——金融数据获取。别看这话题基础&#xff0c;它可是整个量化大厦的地基&#xff0c;地基不稳&#xff0c;再牛的策略都得塌房。我见过太多人&…

构建一个“会思考”的房地产数据获取脚本

—— 跨界思维&#xff1a;从认知自适应到房源信息监测 一、认知科学视角&#xff1a;什么是“会思考” 在心理学与认知科学中&#xff0c;所谓“会思考”&#xff0c;并不是指抽象的哲学推理&#xff0c;而是指个体能在复杂环境中不断调整行动策略。 比如&#xff0c;出行时如…

JavaScript的库简介

JavaScript拥有丰富的库生态系统,类似于Python的requests、numpy或C++的Boost。这些库分为两大类:前端库(如React、Vue)和后端/工具库(如Lodash、Axios)。以下是几个核心库的介绍与用法示例。 常用JavaScript库分类 前端UI库 React:Facebook开发的组件化库,用于构建用…

【无GGuF版本】如何在Colab下T4运行gpt-oss 20B

OpenAI发布了gpt-oss 120B和20B版本。这两个模型均采用Apache 2.0许可证。 特别说明的是&#xff0c;gpt-oss-20b专为低延迟及本地化/专业化场景设计&#xff08;210亿总参数&#xff0c;36亿活跃参数&#xff09;。 由于模型采用原生MXFP4量化训练&#xff0c;使得20B版本即…

LeetCode - LCR 179. 查找总价格为目标值的两个商品

题目 https://leetcode.cn/problems/he-wei-sde-liang-ge-shu-zi-lcof/submissions/660817798/ 思路 解法1是暴力解法&#xff0c;从第一个开始和后面的相加 暴力枚举慢就慢在&#xff0c;这个递增数组是排序好的数组&#xff0c;已经是有序的&#xff0c;暴力解法没有利用这…