粒子群优化是一种基于群体智能的全局优化算法,通过模拟粒子群体的搜索行为来找到最优解。
原理
PSO 通过粒子的位置和速度更新来进行全局搜索,利用个体最优和全局最优信息来指导搜索方向。粒子在搜索空间中飞行,随着时间的推移逐步向个体最佳位置和全局最佳位置靠拢。每个粒子通过以下两个公式更新其速度和位置:
核心公式
- 粒子速度更新:
- 粒子位置更新:
其中:
- vi(t)为粒子 i 在第 t 次迭代的速度
- xi(t) 为粒子 i 在第 t 次迭代的位置
- pi 为粒子 i 的个体最优位置
- g 为全局最优位置
- w 为惯性权重
- c1 为认知常数
- c2 为社会常数
- r1,r2 为随机数,取值范围在 [0, 1] 之间
通过不断迭代更新,粒子群体逐渐趋向全局最优解。
案例1:使用粒子群优化 (PSO) 解决二维函数的最小化问题
在本案例中,我们将使用粒子群优化 (PSO) 算法来找到一个简单的二维函数的最小值。我们将定义一个带有多个局部极小值的函数,并使用PSO算法来进行优化。具体步骤包括函数定义、PSO算法的实现、以及优化过程的可视化。
目标函数
目标函数为二维的Rastrigin函数,这是一个常见的测试函数,用于评估优化算法的性能。Rastrigin函数具有多个局部最小值,但只有一个全局最小值,定义如下:
其中 x 和 y 分别为函数的两个输入变量。该函数的全局最小值为 f(0,0)=0。
Python代码实现
以下是使用PSO算法来优化Rastrigin函数的详细代码实现:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import rcParams
# 设置默认字体
rcParams['font.sans-serif'] = ['SimHei'] # 使用黑体
rcParams['axes.unicode_minus'] = False # 解决负号显示问题
# 定义目标函数(Rastrigin函数)
def rastrigin_function(position):
x, y = position
return 20 + x**2 + y**2 - 10 * (np.cos(2 * np.pi * x) + np.cos(2 * np.pi * y))
# 粒子群优化函数
def pso(objective_function, dimensions, population_size=50, iterations=100, inertia_weight=0.7, cognitive_weight=1.5, social_weight=1.5):
# 初始化粒子群
particles_position = np.random.uniform(-5.12, 5.12, size=(population_size, dimensions))
particles_velocity = np.zeros((population_size, dimensions))
personal_best_position = particles_position.copy()
personal_best_value = np.array([float('inf')] * population_size)
global_best_position = np.zeros(dimensions)
global_best_value = float('inf')
# 记录全局最佳值变化
global_best_values = []
# 迭代指定次数
for t in range(iterations):
# 更新个体最佳
for i in range(population_size):
fitness = objective_function(particles_position[i])
if fitness < personal_best_value[i]:
personal_best_value[i] = fitness
personal_best_position[i] = particles_position[i].copy()
# 更新全局最佳
for i in range(population_size):
if personal_best_value[i] < global_best_value:
global_best_value = personal_best_value[i]
global_best_position = personal_best_position[i].copy()
# 记录全局最优值
global_best_values.append(global_best_value)
# 更新粒子的速度和位置
for i in range(population_size):
r1, r2 = np.random.rand(), np.random.rand()
cognitive_velocity = cognitive_weight * r1 * (personal_best_position[i] - particles_position[i])
social_velocity = social_weight * r2 * (global_best_position - particles_position[i])
particles_velocity[i] = inertia_weight * particles_velocity[i] + cognitive_velocity + social_velocity
particles_position[i] = particles_position[i] + particles_velocity[i]
return global_best_position, global_best_value, global_best_values
# 示例用法
if __name__ == "__main__":
dimensions = 2
population_size = 50
iterations = 100
best_solution, best_value, global_best_values = pso(rastrigin_function, dimensions, population_size, iterations)
print(f"全局最优解: {best_solution}")
print(f"全局最优值: {best_value}")
# 可视化全局最佳值随迭代次数的变化
plt.figure(figsize=(10, 6))
plt.plot(global_best_values, label='全局最优值')
plt.xlabel('迭代次数')
plt.ylabel('全局最优值')
plt.title('全局最优值随迭代次数的变化')
plt.legend()
plt.grid()
plt.show()
# 可视化优化过程
plt.figure(figsize=(8, 6))
plt.scatter(best_solution[0], best_solution[1], color='red', marker='*', label='全局最优解')
plt.scatter(0, 0, color='green', marker='o', label='真实最小值')
plt.title('粒子群优化')
plt.xlabel('X')
plt.ylabel('Y')
plt.legend()
plt.grid(True)
plt.show()
详细步骤解释
- 定义目标函数:
-
- 目标函数定义为Rastrigin函数,具有多个局部最小值和一个全局最小值。
- 初始化粒子群:
-
- 粒子的位置在 [-5.12, 5.12] 区间内随机初始化。
- 粒子的速度初始化为零。
- 记录每个粒子的个体最优位置和全局最优位置。
- 更新个体最佳位置和全局最佳位置:
-
- 对每个粒子,计算其当前的位置的适应度值(即目标函数值)。
- 如果当前适应度值比个体历史最优值更好,则更新个体最优值和位置。
- 如果当前适应度值比全局最优值更好,则更新全局最优值和位置。
- 更新粒子的速度和位置:
-
- 使用公式更新粒子的速度,其中包含惯性部分、认知部分(个体最优位置)和社会部分(全局最优位置)。
- 使用更新后的速度更新粒子的位置。
- 记录全局最优值:
-
- 在每次迭代结束时记录当前的全局最优值,以便后续分析和可视化。
- 迭代过程:
-
- 重复上述步骤直至达到预定的迭代次数。
结果可视化
- 全局最优值随迭代次数的变化:
-
- 绘制全局最优值随迭代次数变化的曲线图,以观察优化过程中的收敛情况。
- 粒子优化过程可视化:
-
- 绘制最终的全局最优解在搜索空间中的位置。
- 比较全局最优解与真实最小值的位置。
通过以上步骤,我们可以全面了解粒子群优化算法在解决复杂函数优化问题中的应用,并通过可视化结果分析其性能和收敛性。
案例2:使用粒子群优化 (PSO) 优化家庭用电计划
在本案例中,我们将使用粒子群优化 (PSO) 算法来优化一个家庭用电计划,以最小化电费。家庭电器有不同的耗电量和使用时间,我们希望找到一个最佳的用电时间安排,以减少电费开支。
问题描述
一个家庭有若干电器,每个电器有固定的功率(单位:千瓦)和使用时长(单位:小时)。电价在一天内分时段波动。我们的目标是根据电价的波动,合理安排电器的使用时间,以最小化总电费。
输入数据
- 电器列表:
-
- 电器1:功率1.5千瓦,使用时长2小时
- 电器2:功率2.0千瓦,使用时长1小时
- 电器3:功率0.5千瓦,使用时长3小时
- 电价列表(24小时,每小时一个电价):
-
- 0.5, 0.5, 0.4, 0.4, 0.3, 0.3, 0.6, 0.6, 0.7, 0.7, 0.8, 0.8,1.0, 1.0, 0.9, 0.9, 0.8, 0.8, 0.7, 0.7, 0.6, 0.6, 0.5, 0.5
目标函数
目标函数为总电费,计算公式如下:
其中 N 为电器数量,Poweri 为电器 i 的功率,Durationi 为电器 i 的使用时长,Pricei 为电器 i 在安排的时间段内的电价。
Python代码实现
以下是使用PSO算法来优化家庭用电计划的详细代码实现:
import numpy as np
import matplotlib.pyplot as plt
# 定义电器和电价
appliances = [
{'power': 1.5, 'duration': 2},
{'power': 2.0, 'duration': 1},
{'power': 0.5, 'duration': 3}
]
prices = [0.5, 0.5, 0.4, 0.4, 0.3, 0.3, 0.6, 0.6, 0.7, 0.7, 0.8, 0.8,
1.0, 1.0, 0.9, 0.9, 0.8, 0.8, 0.7, 0.7, 0.6, 0.6, 0.5, 0.5]
# 定义目标函数(计算总电费)
def total_cost(schedule):
cost = 0.0
for i, appliance in enumerate(appliances):
start_time = int(schedule[i])
for j in range(appliance['duration']):
cost += appliance['power'] * prices[(start_time + j) % 24]
return cost
# 粒子群优化函数
def pso(objective_function, dimensions, population_size=30, iterations=100, inertia_weight=0.7, cognitive_weight=1.5, social_weight=1.5):
# 初始化粒子群
particles_position = np.random.randint(0, 24, size=(population_size, dimensions))
particles_velocity = np.zeros((population_size, dimensions))
personal_best_position = particles_position.copy()
personal_best_value = np.array([float('inf')] * population_size)
global_best_position = np.zeros(dimensions)
global_best_value = float('inf')
# 记录全局最佳值变化
global_best_values = []
# 迭代指定次数
for t in range(iterations):
# 更新个体最佳
for i in range(population_size):
fitness = objective_function(particles_position[i])
if fitness < personal_best_value[i]:
personal_best_value[i] = fitness
personal_best_position[i] = particles_position[i].copy()
# 更新全局最佳
for i in range(population_size):
if personal_best_value[i] < global_best_value:
global_best_value = personal_best_value[i]
global_best_position = personal_best_position[i].copy()
# 记录全局最优值
global_best_values.append(global_best_value)
# 更新粒子的速度和位置
for i in range(population_size):
r1, r2 = np.random.rand(), np.random.rand()
cognitive_velocity = cognitive_weight * r1 * (personal_best_position[i] - particles_position[i])
social_velocity = social_weight * r2 * (global_best_position - particles_position[i])
particles_velocity[i] = inertia_weight * particles_velocity[i] + cognitive_velocity + social_velocity
particles_position[i] = np.clip(particles_position[i] + particles_velocity[i], 0, 23)
return global_best_position, global_best_value, global_best_values
# 示例用法
if __name__ == "__main__":
dimensions = len(appliances)
population_size = 30
iterations = 100
best_schedule, best_cost, global_best_values = pso(total_cost, dimensions, population_size, iterations)
print(f"最佳用电安排时间: {best_schedule}")
print(f"最低总电费: {best_cost}")
# 可视化全局最佳值随迭代次数的变化
plt.figure(figsize=(10, 6))
plt.plot(global_best_values, label='全局最优值')
plt.xlabel('迭代次数')
plt.ylabel('总电费')
plt.title('总电费随迭代次数的变化')
plt.legend()
plt.grid()
plt.show()
详细步骤解释
- 定义电器和电价:
-
- 定义每个电器的功率和使用时长。
- 定义一天24小时的电价波动。
- 定义目标函数:
-
- 目标函数计算总电费,输入为电器使用的开始时间数组。
- 初始化粒子群:
-
- 粒子的位置在 [0, 23] 区间内随机初始化,表示电器的使用开始时间(小时)。
- 粒子的速度初始化为零。
- 记录每个粒子的个体最优位置和全局最优位置。
- 更新个体最佳位置和全局最佳位置:
-
- 对每个粒子,计算其当前安排的总电费(即目标函数值)。
- 如果当前总电费比个体历史最优值更低,则更新个体最优值和位置。
- 如果当前总电费比全局最优值更低,则更新全局最优值和位置。
- 更新粒子的速度和位置:
-
- 使用公式更新粒子的速度,其中包含惯性部分、认知部分(个体最优位置)和社会部分(全局最优位置)。
- 使用更新后的速度更新粒子的位置,并确保位置在 [0, 23] 区间内。
- 记录全局最优值:
-
- 在每次迭代结束时记录当前的全局最优值,以便后续分析和可视化。
结果可视化
- 总电费随迭代次数的变化:
-
- 绘制全局最优值随迭代次数变化的曲线图,以观察优化过程中的收敛情况。
通过以上步骤,我们可以全面了解粒子群优化算法在优化家庭用电计划中的应用,并通过可视化结果分析其性能和收敛性。