写在前面
启发式算法不属于机器学习范畴内的内容,但启发式算法和机器学习有联系,尤其在优化问题和超参数调整中。启发式算法通过规则和经验找到近似解,机器学习则通过数据训练模型。两者结合时,启发式算法可用于特征选择、权重优化等,帮助提升机器学习模型的表现。
1.python基础;
2.ai模型概念+基础;
3.数据预处理;
4.机器学习模型--1.聚类;2.降维;3.回归(预测);4.分类;
5.正则化技术;
6.神经网络模型--1.概念+基础;2.几种常见的神经网络模型;
7.对回归、分类模型的评价方式;
8.简单强化学习概念;
9.几种常见的启发式算法及应用场景;
10.机器学习延申应用-数据分析相关内容--1.A/B Test;2.辛普森悖论;3.蒙特卡洛模拟;
以及其他的与人工智能相关的学习经历,如数据挖掘、计算机视觉-OCR光学字符识别等。
本文目录
启发式算法总述
停机条件
启发式算法的迭代停止条件通常是根据以下情况之一设定的:
- 达到最大迭代次数或计算时间限制。
- 在若干次迭代中目标函数值不再显著变化。
故有可能达不到最优解,结合启发式算法和精确算法。例如,先用启发式算法找到一个高质量的初始解,再用精确算法(如线性规划或整数规划求解器)进一步优化。
群智能算法特性
指无智能的主体通过合作表现出智能行为的特性,在没有集中控制且不提供全局模型的前提下,为寻找复杂的分布式问题求解方案提供了基础。
- 适应度函数(适应度函数):用来衡量个体的优劣,并指导群体的进化。
- 交叉概率(交叉概率):个体之间的交叉概率,控制群体个体之间信息交流的频率。
- 变异概率(变异概率):个体的变异概率,控制群体个体之间信息变异的频率。
群智能算法优点
- 灵活性:群体可以适应随时变换的环境
- 稳健性:即使个体失败,整个群体仍能完成任务
- 自我组织:活动即不受中央控制,也不受局部监管
pulp线性规划求解器
PuLP 是一个用于在 Python 中定义和解决线性规划 (LP) 和整数规划 (IP) 问题的库。它为定义线性规划问题提供了简单的接口,并可以与多个求解器(如 COIN-OR, CPLEX, Gurobi)配合使用。PuLP 的强大之处在于它能够使用 Python 编程的灵活性来定义线性规划模型,并将其转换为标准的数学规划格式,供底层求解器进行优化。
代码
import pulp
# 创建一个线性规划问题实例(最大化问题)
prob = pulp.LpProblem("Maximize_Profit", pulp.LpMaximize)
# 定义决策变量A和B,均为非负
A = pulp.LpVariable('A', lowBound=0, cat='Continuous')
B = pulp.LpVariable('B', lowBound=0, cat='Continuous')
# 定义目标函数
prob += 40 * A + 30 * B, "Total_Profit"
# 定义约束条件
prob += 2 * A + 1 * B <= 8, "Labor_Constraint"
prob += 3 * A + 2 * B <= 12, "Material_Constraint"
# 求解问题
prob.solve()
# 输出结果
print("Status:", pulp.LpStatus[prob.status])
# 输出解
print(f"Optimal number of product A to produce: {A.varValue}")
print(f"Optimal number of product B to produce: {B.varValue}")
# 输出最大利润
print(f"Maximum Profit: {pulp.value(prob.objective)}")
- 定义问题:通过 pulp.LpProblem("问题名称", pulp.LpMaximize) 定义一个线性规划的最大化问题。
- 决策变量:定义了两个决策变量。
- 𝐴和𝐵,代表生产的产品数量,它们都是非负的连续变量。
- 目标函数:我们通过 prob += 40 * A + 30 * B, "Total_Profit" 来定义目标函数,表示最大化利润。
- 约束条件:通过 prob += 添加约束条件,例如劳动时间和原材料的限制。
- 求解:使用 prob.solve() 调用默认的 COIN-OR 求解器来解决线性规划问题。
- 输出结果:通过 A.varValue 和 B.varValue 获取最优解,通过 pulp.value(prob.objective) 获取最大化的利润。
输出:
Welcome to the CBC MILP Solver
Version: 2.10.3
Build Date: Dec 15 2019
At line 2 NAME MODEL
At line 3 ROWS
At line 7 COLUMNS
At line 14 RHS
At line 17 BOUNDS
At line 18 ENDATA
Problem MODEL has 2 rows, 2 columns and 4 elements
Coin0008I MODEL read with 0 errors
Option for timeMode changed from cpu to elapsed
Presolve 2 (0) rows, 2 (0) columns and 4 (0) elements
0 Obj -0 Dual inf 85 (2)
0 Obj -0 Dual inf 85 (2)
1 Obj 180
Optimal - objective value 180
Optimal objective 180 - 1 iterations time 0.002
Option for printingOptions changed from normal to all
Total time (CPU seconds): 0.01 (Wallclock seconds): 0.02
Status: Optimal
Optimal number of product A to produce: 0.0
Optimal number of product B to produce: 6.0
Maximum Profit: 180.0
粒子群算法(PSO)
粒子群算法(PSO)是群智能算法的一种,它通过模拟自然界中生物群体的行为来搜索最优解。是基于迭代的方法
原理
- 鸟群:假设一个区域,所有的鸟都不知道食物的位置,但是它们知道当前位置离食物还有多远
- PSO:每个解看作一只鸟,称为粒子,所有粒子都有一个适应值(由目标函数决定),每个粒子都有一个速度决定它们的飞翔方向和距离,粒子们追随当前最优粒子在解空间中搜索。粒子们知道当前自己的位置和自己已发现的最好位置(pbest)以及所有pbest中最好的gbest。粒子通过自己的经验和同伴中最好的经验来决定下一步的运动。
参数 (利用网格搜索法确定最佳)
- 粒子数:粒子群的大小,一般取20-40,对于较难或特定类别的问题可以取100-200(若过小:结果不准;过大:效率很慢);
- 最大速度:决定粒子在一个循环中最大的移动距离,通常设定为粒子的范围宽度(若过大,可能结果会不在有效范围之内);
- 终止条件:最大循环数以及最小错误要求;
- 惯性权重:w,控制粒子的搜索范围,有能力探索新的区域,较大的w有利于跳出局部极值,而较小的有利于算法收敛。因此随着迭代的进行,线性的减小w: 其中,、:w的最大最小值;:最大迭代次数;:当前迭代次数;
- c1、c2:加速因子,两个大于0的常数,属于0-1之间,将粒子推向统计加速项的权重,较大会导致粒子突然冲向或越过目标区域,较小则允许粒子再被拉回之前在目标区域外徘徊;
- 控制参数fac=c1+c2,fac越大,则粒子的位置变化越快;实验证明fac=4.1(通常c1=2.0,c2=2.0)具有很好的收敛效果;
第i个粒子的速度
v(i+1) = w * v(i) + c1 * r1(i) * (pbest(i) - x(i)) + c2 * r2(i) * (gbest - x(i)), 其中:
- w、c1、c2是超参数,r1、r2是随机数;
- x(i)是第i个粒子的位置,v(i-1)是第i-1个粒子的速度,pbest(i)是第i个粒子的最佳位置,gbest是所有pbest中最好的位置。
- 整个c1项为认知部分,即来源于自己的经验部分;c2项为社会部分,即来源于群体中其他优秀微粒的经验;c1越大,则粒子越容易接受认知信息,c2越大,则粒子越容易接受社会信息。
第i个粒子的位置
x(i+1) = x(i) + v(i)
算法步骤
- 初始化:随机生成一组粒子,并赋予其初始位置和速度。
- 评估:计算每个粒子的适应度值,即目标函数值。
- 选择:根据适应度值选择出最优的粒子。
- 交换:将最优的粒子的位置和速度信息传递给其他粒子。(设置最优的pbest为gbest)
- 更新:根据最优的粒子的位置信息更新粒子的位置和速度信息。
- 重复:重复步骤2-5,直到收敛(全局最优解)或达到最大迭代次数。
优点
- 需要调整的参数相对较少;
- 适用于连续和离散的优化问题,能处理多维、复杂约束的优化问题;
- 可以很容易地进行并行处理。
缺点
- 粒子群算法的收敛速度慢,在大型问题中,需要较多的迭代次数才能找到全局最优解;
- 粒子群算法的初始条件很敏感,依赖于这些参数的设置,初始条件的选择会影响最终的结果;
- 粒子群算法依赖于初始解,初始解的选择会影响最终的结果。
适应问题类型
- 连续优化问题:PSO 特别适合连续解空间的问题,如函数优化、参数估计等。它通过粒子的速度和位置更新,能够快速找到近似最优解。
- 多峰优化问题:PSO 可以处理具有多个峰值的复杂优化问题,通过全局和局部搜索的结合,较好地避免陷入局部最优。
- 动态优化问题:PSO 能够适应动态变化的环境,通过粒子位置和速度的实时更新来应对目标函数的变化。
典型应用场景
- 控制系统优化:在机器人控制、自动驾驶、无人机导航等领域,PSO 可以用于优化控制策略和路径规划。
- 信号处理和图像处理:用于滤波器设计、图像分割、特征提取等问题。
- 经济和金融领域:如投资组合优化、金融时间序列预测、市场模型优化等。
代码 寻找Rastrigin函数的最小值位置
Rastrigin函数:具有多个局部最小值,适合测试优化算法的性能。
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
# 定义目标函数(Rastrigin函数)
def objective_function(x):
return x[0]**2 + x[1]**2 - 10 * np.cos(2 * np.pi * x[0]) - 10 * np.cos(2 * np.pi * x[1]) + 20
# 粒子群算法参数
num_particles = 30 # 粒子数量
num_iterations = 100 # 迭代次数
dim = 2 # 维度
w = 0.5 # 惯性权重
c1 = 1.5 # 个体学习因子
c2 = 1.5 # 社会学习因子
# 初始化粒子位置和速度
particles_position = np.random.uniform(-5.12, 5.12, (num_particles, dim))
particles_velocity = np.random.uniform(-1, 1, (num_particles, dim))
# 初始化个体最优位置和全局最优位置
personal_best_position = particles_position.copy()
personal_best_value = np.apply_along_axis(objective_function, 1, personal_best_position)
global_best_position = personal_best_position[np.argmin(personal_best_value)]
global_best_value = np.min(personal_best_value)
# PSO算法迭代
for _ in range(num_iterations):
r1 = np.random.rand(num_particles, dim)
r2 = np.random.rand(num_particles, dim)
particles_velocity = (w * particles_velocity +
c1 * r1 * (personal_best_position - particles_position) +
c2 * r2 * (global_best_position - particles_position))
particles_position += particles_velocity
current_value = np.apply_along_axis(objective_function, 1, particles_position)
better_mask = current_value < personal_best_value
personal_best_position[better_mask] = particles_position[better_mask]
personal_best_value[better_mask] = current_value[better_mask]
if np.min(personal_best_value) < global_best_value:
global_best_position = personal_best_position[np.argmin(personal_best_value)]
global_best_value = np.min(personal_best_value)
# 输出最优解
print("Global Best Position:", global_best_position)
print("Global Best Value:", global_best_value)
# 绘制函数的3D图像
X = np.linspace(-5.12, 5.12, 400)
Y = np.linspace(-5.12, 5.12, 400)
X, Y = np.meshgrid(X, Y)
Z = X**2 + Y**2 - 10 * np.cos(2 * np.pi * X) - 10 * np.cos(2 * np.pi * Y) + 20
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot_surface(X, Y, Z, cmap='viridis')
# 标记出全局最优解
ax.scatter(global_best_position[0], global_best_position[1], global_best_value, color='r', s=100)
ax.set_title('Rastrigin Function')
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
plt.show()
输出:
Global Best Position: [-1.36850095e-10 -1.20921201e-10]
Global Best Value: 0.0
对于梯度的介绍,我在《6.1神经网络基础》中具体介绍过。
模拟退火算法(SA)
用了蒙特卡洛优化(在《8.强化学习》中具体介绍过)方法,是对爬山算法的一种改进;
爬山算法
简单的贪心搜索算法,从当前黑的临近空间解中选择一个最优解作为当前解直到局部最优,但不一定能达到全局最优。
原理
模拟退火算法来源于固体退火原理,引入温度这一变量初始状态设计一个高温,升温内能增大,非最优解也会愿意尝试;随着温度下降,粒子趋于有序,尝试的活性下降。相对于爬山算法,增大了找到全局最优解的概率
是一个双重迭代的算法:
- 外循环:退火过程(模拟温度下降的过程);
- 内循环:Metropolis算法(模拟某一温度下粒子的跳动过程)。
内循环中随机移动后的解如果更好(增量大于0)就接受他,更新位置;如果结果更差(增量小于0),就以p的概率()接受他(产生随机概率值(0<r<1),如果p>r则接受新解,否则接受旧解)。内循环的最后再更新温度。
优点
- 有概率跳出局部最优解并趋于全局最优;
- 可以灵活调整参数以平衡搜索质量和速度;
- 能处理复杂的连续或离散优化问题;
- 解和初始状态无关。
缺点
- 不同的问题可能需要不同的设置,需要合适的初始解和参数调整;
- 搜索空间的复杂性:搜索空间越大,算法的收敛速度越慢,可能碰到的局部最优解最多;
- 运行结果受随机概率影响可能有一定变化,随机性强;
- SA与其他优化算法不同,不需要初始化种群操作,收敛速度慢。
适应的问题类型
- 复杂的组合优化问题:SA 适用于需要全局搜索能力的复杂组合优化问题,尤其是目标函数具有多个局部最优解时,如大规模的旅行商问题。
- 非线性和非凸优化问题:SA 在处理非凸函数优化时表现良好,适用于那些目标函数可能具有多个局部最优的非线性问题。
- 目标函数不光滑或不可导的优化问题:SA 不依赖于目标函数的导数信息,适用于优化不可导函数或目标函数不光滑的问题。
典型应用场景
- 资源配置和调度问题:如生产调度、物流运输优化、任务调度等,需要在多个可能解中找到最优配置。
- 电路设计:用于优化复杂电路的参数设置和布局设计。
- 生物信息学和物理学问题:如蛋白质折叠、晶体结构预测等问题,这些问题通常具有复杂的能量表面。
double T = 2000; // 初始温度
double dT = 0.99; // 降温速率,越接近1降温越慢
double eps = 1e-14; // 终止温度,越小越好
while (T > eps) {
// 这里是每次退火的操作,例如:
// 1. 生成新解
// 2. 计算新解的代价
// 3. 根据代价和当前温度决定是否接受新解,有一定概率接受比当前解较差的解
T *= dT; // 降温 T减小,接受较差解的概率减小
}
代码 寻找Rastrigin函数的最小值位置
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
# 定义Rastrigin函数作为目标函数
def objective_function(x):
return x[0]**2 + x[1]**2 - 10 * np.cos(2 * np.pi * x[0]) - 10 * np.cos(2 * np.pi * x[1]) + 20
# 邻域函数,产生一个新的二维解
def neighbor(x):
return x + np.random.normal(0, 1, size=2) # 生成一个二维向量
# 模拟退火算法
def simulated_annealing(objective_function, initial_solution, temp, cooling_rate, max_iterations, inner_iterations):
current_solution = initial_solution
current_value = objective_function(current_solution)
best_solution = current_solution
best_value = current_value
for iteration in range(max_iterations):
for _ in range(inner_iterations):
# 生成新解
new_solution = neighbor(current_solution)
new_value = objective_function(new_solution)
# 根据概率判断是否接受新解
if new_value < current_value or np.random.rand() < np.exp(-(new_value - current_value) / temp):
current_solution = new_solution
current_value = new_value
# 更新最优解
if current_value < best_value:
best_solution = current_solution
best_value = current_value
# 降低温度
temp *= cooling_rate
print(f'Iteration {iteration + 1}, Temp: {temp:.4f}, Best Value: {best_value:.4f}')
return best_solution, best_value
# 参数设置
initial_solution = np.random.uniform(-5.12, 5.12, size=2) # 初始解,二维
initial_temp = 100 # 初始温度
cooling_rate = 0.9 # 降温速率
max_iterations = 50 # 最大外循环次数
inner_iterations = 10 # 每次降温时的内循环次数
# 运行模拟退火算法
best_solution, best_value = simulated_annealing(objective_function, initial_solution, initial_temp, cooling_rate, max_iterations, inner_iterations)
# 输出最优解
print("Best Solution:", best_solution)
print("Best Value:", best_value)
# 绘制Rastrigin函数的三维图像
X = np.linspace(-5.12, 5.12, 400)
Y = np.linspace(-5.12, 5.12, 400)
X, Y = np.meshgrid(X, Y)
Z = X**2 + Y**2 - 10 * np.cos(2 * np.pi * X) - 10 * np.cos(2 * np.pi * Y) + 20
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot_surface(X, Y, Z, cmap='viridis')
# 标记出模拟退火算法找到的最优解
ax.scatter(best_solution[0], best_solution[1], best_value, color='r', s=100)
ax.set_title('Rastrigin Function with Simulated Annealing')
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
plt.show()
输出:
Iteration 1, Temp: 90.0000, Best Value: 16.0347
Iteration 2, Temp: 81.0000, Best Value: 13.4949
Iteration 3, Temp: 72.9000, Best Value: 13.4949
Iteration 4, Temp: 65.6100, Best Value: 13.4949
Iteration 5, Temp: 59.0490, Best Value: 13.4949
Iteration 6, Temp: 53.1441, Best Value: 13.4949
Iteration 7, Temp: 47.8297, Best Value: 13.4949
Iteration 8, Temp: 43.0467, Best Value: 13.4949
Iteration 9, Temp: 38.7420, Best Value: 13.4949
Iteration 10, Temp: 34.8678, Best Value: 13.4949
Iteration 11, Temp: 31.3811, Best Value: 13.4949
Iteration 12, Temp: 28.2430, Best Value: 13.4949
Iteration 13, Temp: 25.4187, Best Value: 8.5710
Iteration 14, Temp: 22.8768, Best Value: 5.9105
Iteration 15, Temp: 20.5891, Best Value: 5.9105
Iteration 16, Temp: 18.5302, Best Value: 5.9105
Iteration 17, Temp: 16.6772, Best Value: 5.9105
Iteration 18, Temp: 15.0095, Best Value: 5.9105
Iteration 19, Temp: 13.5085, Best Value: 5.9105
Iteration 20, Temp: 12.1577, Best Value: 5.9105
Iteration 21, Temp: 10.9419, Best Value: 5.9105
Iteration 22, Temp: 9.8477, Best Value: 5.9105
Iteration 23, Temp: 8.8629, Best Value: 5.9105
Iteration 24, Temp: 7.9766, Best Value: 5.9105
Iteration 25, Temp: 7.1790, Best Value: 2.2807
Iteration 26, Temp: 6.4611, Best Value: 1.8803
Iteration 27, Temp: 5.8150, Best Value: 1.8803
Iteration 28, Temp: 5.2335, Best Value: 1.8803
Iteration 29, Temp: 4.7101, Best Value: 1.8803
Iteration 30, Temp: 4.2391, Best Value: 1.8803
Iteration 31, Temp: 3.8152, Best Value: 1.8803
Iteration 32, Temp: 3.4337, Best Value: 0.4254
Iteration 33, Temp: 3.0903, Best Value: 0.4254
Iteration 34, Temp: 2.7813, Best Value: 0.4254
Iteration 35, Temp: 2.5032, Best Value: 0.4254
Iteration 36, Temp: 2.2528, Best Value: 0.4254
Iteration 37, Temp: 2.0276, Best Value: 0.4254
Iteration 38, Temp: 1.8248, Best Value: 0.4254
Iteration 39, Temp: 1.6423, Best Value: 0.4254
Iteration 40, Temp: 1.4781, Best Value: 0.4254
Iteration 41, Temp: 1.3303, Best Value: 0.4254
Iteration 42, Temp: 1.1973, Best Value: 0.4254
Iteration 43, Temp: 1.0775, Best Value: 0.4254
Iteration 44, Temp: 0.9698, Best Value: 0.4254
Iteration 45, Temp: 0.8728, Best Value: 0.4254
Iteration 46, Temp: 0.7855, Best Value: 0.4254
Iteration 47, Temp: 0.7070, Best Value: 0.4254
Iteration 48, Temp: 0.6363, Best Value: 0.4254
Iteration 49, Temp: 0.5726, Best Value: 0.4254
Iteration 50, Temp: 0.5154, Best Value: 0.4254
Best Solution: [0.01949567 0.04213167]
Best Value: 0.42543128700373956
遗传算法(GA)
同样用了蒙特卡洛优化(在《8.强化学习》中具体介绍过)方法。
概念
- 染色体:问题中个体的某种字符串形式的编码表示;
- 基因:染色体(字符串)中的单个字符。
算法步骤
- 初始化种群:设定种群规模,编码染色体,产生厨师种群。随机生成N个染色体,每个染色体由N个基因组成。
- 计算适应度:定义适应度函数,对于每个染色体,计算其对应的适应度值(代入到目标函数中的值),适应度值越高,染色体的优劣程度越高。
- 判断是否终止(迭代次数或误差最小的那一项满足条件)。
- 选择-复制:对于一个规模为N的种群S,按每个染色体的选择概率P=f(xi)/求和f(xj)[j从1到N]所决定的选择机会,分N次从S中随机选定1个染色体(赌轮选择法),并进行复制,组成群体S1。其中,f:目标函数,即适应度值。
- 交叉:按交叉率从S1中随机确定c个染色体,配对进行交叉操作,产生新的染色体代替原染色体,得到S2。
- 变异:按变异率从S2中随机确定m个染色体,分别进行变异操作,产生新的染色体代替原染色体,得到S3。
- 生成新一代种群,即S3。迭代次数加一。
- 迭代:重复步骤2-7,直到满足终止条件。
控制参数
- 种群大小N:种群的大小决定了算法的复杂度。
- 最大换代数(可理解为迭代次数)。
- 交叉率(crossover rate):参加交叉运算的染色体个数占全体染色体总数的比例,记为Pc,一般取0.4-0.99。
- 变异率(mutation rate):发生变异的基因位数所占全体染色体的基因总位数的比例,记为Pm,一般取0.0001-0.1。
- 如计算可以变异的基因位数:4(个染色体)*5(位基因)*Pm=0.0001*4*5=0.002,不足一位,所以本轮遗传操作不变异。
优点
- 全局搜索能力强:GA 通过模拟自然选择和遗传变异过程,具有较强的全局搜索能力,能够有效探索解空间。
- 适应性强:GA 能够处理复杂的非线性、多峰优化问题,适用于广泛的应用场景。
- 多样性维护:GA 通过种群多样性保持(如交叉、变异等操作),能够避免过早收敛到局部最优解。
- 无需梯度信息:GA 不需要目标函数的梯度信息,适合处理不可导或不连续的优化问题。
缺点
- 收敛速度较慢:GA 的进化过程往往需要较多的迭代次数,导致整体收敛速度较慢,尤其是在优化问题较复杂时。
- 参数设置复杂:GA 需要设置较多参数,如种群大小、交叉概率、变异概率等,这些参数的选择对算法性能有较大影响。
- 易陷入局部最优:尽管 GA 具有全局搜索能力,但在复杂问题中,种群可能会逐渐趋同,导致陷入局部最优解。
- 计算代价较高:由于需要维护和操作一个种群,GA 的计算开销较大,尤其是在大规模问题中。
适应问题类型
- 组合优化问题:如旅行商问题(TSP)、背包问题、排课问题、工厂调度问题等,这类问题通常有离散的解空间,GA 的种群多样性和进化机制使其能够有效探索这些复杂的解空间。
- 非线性优化问题:遗传算法适用于处理复杂的非线性优化问题,尤其是在目标函数具有多个局部最优解的情况下。
- 多目标优化问题:GA 可以同时处理多个目标,通过进化机制生成一组解,满足不同目标的平衡。
- 规则发现和符号回归:GA 可以用来发现数据中的规则,或进行符号回归,从而在数据中找到潜在的函数关系。
典型应用场景
- 人工智能和机器学习:用于特征选择、超参数优化、神经网络结构优化等。
- 工程设计优化:如结构优化、机械设计、电子电路设计等需要考虑多目标的复杂工程问题。
- 生物信息学:基因序列比对、基因组拼接、蛋白质结构预测等。
代码 寻找Rastrigin函数的最小值位置
- 适应度函数:将 Rastrigin 函数定义为优化目标(注意在遗传算法中为了选择最大值,这里用负值做适应度)
- 种群初始化:生成二维的解(
x
和y
)。 - 交叉操作和变异操作:这些操作都在二维向量上进行。
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
# 定义Rastrigin函数作为目标函数
def fitness_function(x):
return -(x[0]**2 + x[1]**2 - 10 * np.cos(2 * np.pi * x[0]) - 10 * np.cos(2 * np.pi * x[1]) + 20)
# 初始化种群,二维
def initialize_population(size, x_min, x_max):
return np.random.uniform(x_min, x_max, (size, 2))
# 选择父代(轮盘赌选择法)
def select_parents(population, fitness_values):
total_fitness = np.sum(fitness_values)
selection_prob = fitness_values / total_fitness
selected_idx = np.random.choice(len(population), size=len(population), p=selection_prob)
return population[selected_idx]
# 交叉操作
def crossover(parent1, parent2):
alpha = np.random.rand()
return alpha * parent1 + (1 - alpha) * parent2
# 变异操作
def mutate(child, mutation_rate, x_min, x_max):
if np.random.rand() < mutation_rate:
return np.random.uniform(x_min, x_max, size=2)
return child
# 遗传算法主循环
def genetic_algorithm(pop_size, x_min, x_max, generations, mutation_rate):
population = initialize_population(pop_size, x_min, x_max)
for generation in range(generations):
fitness_values = np.array([fitness_function(x) for x in population])
parents = select_parents(population, fitness_values)
next_generation = []
for i in range(0, pop_size, 2):
parent1, parent2 = parents[i], parents[i+1]
child1, child2 = crossover(parent1, parent2), crossover(parent2, parent1)
child1, child2 = mutate(child1, mutation_rate, x_min, x_max), mutate(child2, mutation_rate, x_min, x_max)
next_generation.extend([child1, child2])
population = np.array(next_generation)
# 返回最优解
best_individual = population[np.argmax([fitness_function(x) for x in population])]
best_fitness = fitness_function(best_individual)
return best_individual, best_fitness
# 参数设置
pop_size = 20
x_min, x_max = -5.12, 5.12
generations = 100
mutation_rate = 0.1
# 运行遗传算法
best_solution, best_fitness = genetic_algorithm(pop_size, x_min, x_max, generations, mutation_rate)
print(f"最优解: x = {best_solution}, 适应度值 = {best_fitness}")
# 绘制Rastrigin函数的三维图像
X = np.linspace(-5.12, 5.12, 400)
Y = np.linspace(-5.12, 5.12, 400)
X, Y = np.meshgrid(X, Y)
Z = X**2 + Y**2 - 10 * np.cos(2 * np.pi * X) - 10 * np.cos(2 * np.pi * Y) + 20
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot_surface(X, Y, Z, cmap='viridis')
# 标记出遗传算法找到的最优解
ax.scatter(best_solution[0], best_solution[1], -best_fitness, color='r', s=100) # -best_fitness,因为fitness是负值
ax.set_title('Rastrigin Function with Genetic Algorithm')
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
plt.show()
输出:
最优解: x = [-0.92258478 -1.0867697 ], 适应度值 = -4.641796195714294
PSO、SA、GA对比总结
不同
- 并行:PSO可(粒子的独立性),SA不可(串行降温),GA部分可(按种群分为子种群);
- 搜索机制:PSO通过群体合作和个体经验共享搜索最优解,SA利用概率性接受劣解的机制寻找最优解,GA模拟自然选择和遗传变异,通过交叉和变异等操作产生新解;
- 全局最优:PSO相对表现最差;
- 初始条件依赖性:PSO对初始解和参数敏感,SA初始温度和冷却速率的选择对算法结果有较大影响,GA对初始种群的多样性要求较高;
- 收敛速度:PSO通常在早期收敛速度较快,而GA和SA的收敛速度相对较慢。SA在搜索后期的收敛速度尤其慢,因为温度逐渐降低,导致搜索步长减小。
相同
- 适应性:三者都有很强的适应性;
- 都是从任一解出发,按照某种机制,以一定概率在整个求解空间中探索最优解。
TOPSIS,NSGA-II组合算法
TOPSIS(Technique for Order Preference by Similarity to Ideal Solution)和NSGA-II(Non-dominated Sorting Genetic Algorithm II)的组合算法是一种将多标准决策分析和进化算法结合的优化方法,用于解决复杂的多目标优化问题。它们的结合能够兼顾多个冲突目标,得到接近最优解的 Pareto 前沿,同时提供具体方案的优劣排序。
TOPSIS
TOPSIS 是一种经典的多标准决策分析方法,其基本思想是通过计算各备选方案与“理想解”和“负理想解”的距离,来对备选方案进行排序。理想解是各指标的最好值,负理想解是各指标的最差值。TOPSIS 的步骤如下:
- 标准化决策矩阵:将所有指标标准化,使得它们具有可比性。
- 加权标准化矩阵:考虑各指标的重要性,乘以权重。
- 计算理想解和负理想解:找到各指标的最大值和最小值,分别构成理想解和负理想解。
- 计算与理想解和负理想解的欧几里得距离。
- 计算相对接近度:根据与理想解和负理想解的距离计算每个方案的相对接近度,距离越小方案越优。
- 排序:根据相对接近度对所有方案进行排序。
TOPSIS 可以帮助决策者在多个方案中找到离最优解最近的方案,但它仅适合处理多个目标指标,并不具备全局优化的能力。
NSGA-II
NSGA-II 是一种常用于多目标优化的进化算法。它通过模拟自然选择和遗传操作来逐步进化出一组解决方案,称为 Pareto 前沿解,即一组在所有目标上都互相不被严格支配的解。NSGA-II 的步骤包括:
- 初始化:随机生成一组种群。
- 非支配排序:根据 Pareto 优势关系对种群进行分层,生成非支配排序层级。
- 拥挤度排序:在同一层内使用拥挤度距离来保持解的多样性。
- 选择、交叉、变异:使用选择、交叉、变异操作生成下一代种群。
- 迭代更新:重复非支配排序和拥挤度排序,最终得到分布均匀的 Pareto 前沿。
NSGA-II 能有效处理多个目标之间的冲突,得到一个多样化的解集,但它不提供对每个解的具体排序。
TOPSIS 和 NSGA-II 的组合算法
将 TOPSIS 和 NSGA-II 结合,可以将 NSGA-II 生成的 Pareto 前沿解进一步细化和排序,帮助决策者在 Pareto 解集内做出具体的选择。具体步骤如下:
- 使用 NSGA-II 生成 Pareto 前沿:先使用 NSGA-II 生成一组非支配的 Pareto 前沿解。
- 对 Pareto 前沿解进行 TOPSIS 处理:将 Pareto 前沿解输入 TOPSIS 算法,根据距离理想解的接近度,对解进行排序。
- 综合考虑权重和距离:TOPSIS 能根据权重分配和指标优化目标,帮助决策者在 Pareto 前沿解集中做出更加合理的选择。
这种组合算法的优势在于 NSGA-II 提供了解的多样性,而 TOPSIS 提供了从多目标中优中选优的能力。
应用场景
这种算法组合在实际中常用于复杂的多目标优化问题,比如供应链优化、投资组合优化、工程设计等,需要在多个冲突目标之间进行权衡时使用。
总结
pulp求解器是一种基于线性规划的优化工具,能够在确定性条件下为线性或整数规划问题找到全局最优解。与此相比,启发式算法如粒子群优化(PSO)、模拟退火(SA)、遗传算法(GA)等则是基于生物或物理学启发的非确定性方法,通常用于解决复杂的非线性或高维度问题。这些算法通过随机性和局部搜索探索解空间,逐步逼近最优解,虽然不一定保证全局最优,但在处理高复杂度问题时通常能提供有效的近似解。