狼群算法实战:用Python从零实现智能优化(附完整代码)

自然界中狼群的协作捕猎行为启发了众多智能优化算法的设计。狼群算法(Wolf Pack Algorithm, WPA)通过模拟狼群的社会分工和捕猎策略,展现出强大的全局搜索能力。本文将带您从零开始实现这一算法,并通过可视化展示其优化过程。

1. 算法核心原理拆解

狼群算法的精髓在于将狼群的社会结构转化为数学建模。狼群中主要包含三类角色:

  • 头狼(Leader):当前适应度最优的个体,负责指挥群体行动
  • 探狼(Scouter):负责探索未知区域,寻找更优解
  • 猛狼(Follower):响应头狼召唤,向最优位置聚集

算法通过以下三种智能行为实现优化:

# 伪代码展示算法流程
def wolf_pack_optimization():
    initialize_population()  # 初始化狼群
    while not stopping_condition:
        scout_phase()       # 探狼游走搜索
        summon_phase()      # 猛狼奔袭
        siege_phase()       # 群体围攻
        update_hierarchy()  # 更新头狼
        population_renew()  # 群体更新
    return best_solution

三种行为对应的数学表达:

行为类型 位置更新公式 参数说明
游走行为 $x_{id}^p = x_{id} + sin(2π×p/h)×step_a^d$ p:方向序号, h:总方向数
召唤行为 $x_{id}^{k+1} = x_{id}^k + step_b^d⋅\frac{(g_d^k−x_{id}^k)}{ g_d^k−x_{id}^k
围攻行为 $x_{id}^{k+1} = x_{id}^k + λ⋅step_c^d⋅ G_d^k−x_{id}^k

2. Python实现详解

2.1 基础框架搭建

首先构建算法的主框架,包含必要的类和基本方法:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation

class WolfPackAlgorithm:
    def __init__(self, objective_func, dim, lb, ub, 
                 pop_size=50, max_iter=100,
                 alpha=0.5, beta=0.5, delta=0.5):
        """
        初始化狼群算法参数
        :param objective_func: 目标函数
        :param dim: 问题维度
        :param lb: 变量下界
        :param ub: 变量上界
        :param pop_size: 种群规模
        :param max_iter: 最大迭代次数
        :param alpha: 探狼比例因子
        :param beta: 群体更新因子
        :param delta: 步长调节因子
        """
        self.obj_func = objective_func
        self.dim = dim
        self.lb = lb
        self.ub = ub
        self.pop_size = pop_size
        self.max_iter = max_iter
        self.alpha = alpha
        self.beta = beta
        self.delta = delta
        
        # 初始化种群
        self.population = np.random.uniform(lb, ub, (pop_size, dim))
        self.fitness = np.array([self.obj_func(ind) for ind in self.population])
        self.leader_idx = np.argmin(self.fitness)
        self.leader_pos = self.population[self.leader_idx].copy()
        self.leader_fit = self.fitness[self.leader_idx]
        
        # 记录优化过程
        self.history = {
            'positions': [],
            'fitness': [],
            'leader_pos': []
        }

2.2 核心行为实现

探狼游走行为
def scout_phase(self, T_max=10):
    # 确定探狼数量
    S_num = np.random.randint(
        int(self.pop_size/(self.alpha+1)), 
        int(self.pop_size/self.alpha)+1
    )
    
    # 选择适应度较好的个体作为探狼(排除头狼)
    scout_indices = np.argsort(self.fitness)[1:S_num+1]
    
    for idx in scout_indices:
        improved = False
        for t in range(T_max):
            # 随机选择游走方向
            h = np.random.randint(4, 8)  # 方向数
            p = np.random.randint(1, h+1)
            
            # 计算游走步长
            step_a = (self.ub - self.lb) / (10 * self.delta)
            
            # 更新位置
            new_pos = self.population[idx] + \
                     np.sin(2*np.pi*p/h) * step_a
            
            # 边界处理
            new_pos = np.clip(new_pos, self.lb, self.ub)
            
            # 评估新位置
            new_fit = self.obj_func(new_pos)
            
            if new_fit < self.fitness[idx]:
                self.population[idx] = new_pos
                self.fitness[idx] = new_fit
                improved = True
                
                # 检查是否成为头狼
                if new_fit < self.leader_fit:
                    self.leader_idx = idx
                    self.leader_pos = new_pos.copy()
                    self.leader_fit = new_fit
                    break
            
        if not improved:
            # 未改进则随机移动
            self.population[idx] += np.random.uniform(-1, 1, self.dim) * step_a
            self.population[idx] = np.clip(self.population[idx], self.lb, self.ub)
            self.fitness[idx] = self.obj_func(self.population[idx])
猛狼召唤行为
def summon_phase(self):
    # 猛狼数量为剩余个体
    follower_indices = [i for i in range(self.pop_size) 
                       if i != self.leader_idx]
    
    step_b = (self.ub - self.lb) / (5 * self.delta)  # 奔袭步长
    
    for idx in follower_indices:
        # 计算与头狼的距离
        dist = np.linalg.norm(self.population[idx] - self.leader_pos)
        
        # 距离判定因子
        d_near = np.sum(self.ub - self.lb) / (self.dim * 10)
        
        if dist > d_near:
            # 向头狼移动
            direction = (self.leader_pos - self.population[idx]) / \
                       (dist + 1e-10)  # 避免除以零
            new_pos = self.population[idx] + step_b * direction
            
            # 边界处理
            new_pos = np.clip(new_pos, self.lb, self.ub)
            
            # 评估新位置
            new_fit = self.obj_func(new_pos)
            
            if new_fit < self.fitness[idx]:
                self.population[idx] = new_pos
                self.fitness[idx] = new_fit
                
                # 检查是否成为头狼
                if new_fit < self.leader_fit:
                    self.leader_idx = idx
                    self.leader_pos = new_pos.copy()
                    self.leader_fit = new_fit
群体围攻行为
def siege_phase(self):
    step_c = (self.ub - self.lb) / (20 * self.delta)  # 攻击步长
    
    for idx in range(self.pop_size):
        if idx == self.leader_idx:
            continue
            
        # 随机扰动系数
        lambda_ = np.random.uniform(-1, 1, self.dim)
        
        # 更新位置
        new_pos = self.population[idx] + \
                 lambda_ * step_c * np.abs(self.leader_pos - self.population[idx])
        
        # 边界处理
        new_pos = np.clip(new_pos, self.lb, self.ub)
        
        # 评估新位置
        new_fit = self.obj_func(new_pos)
        
        if new_fit < self.fitness[idx]:
            self.population[idx] = new_pos
            self.fitness[idx] = new_fit
            
            # 检查是否成为头狼
            if new_fit < self.leader_fit:
                self.leader_idx = idx
                self.leader_pos = new_pos.copy()
                self.leader_fit = new_fit

2.3 群体更新机制

def population_renew(self):
    # 确定淘汰数量
    R = np.random.randint(
        int(self.pop_size/(2*self.beta)),
        int(self.pop_size/self.beta)+1
    )
    
    # 淘汰适应度最差的R匹狼
    worst_indices = np.argsort(self.fitness)[-R:]
    
    # 生成新个体
    self.population[worst_indices] = np.random.uniform(
        self.lb, self.ub, (R, self.dim)
    )
    self.fitness[worst_indices] = [self.obj_func(ind) 
                                  for ind in self.population[worst_indices]]
    
    # 更新头狼
    new_leader_idx = np.argmin(self.fitness)
    if self.fitness[new_leader_idx] < self.leader_fit:
        self.leader_idx = new_leader_idx
        self.leader_pos = self.population[new_leader_idx].copy()
        self.leader_fit = self.fitness[new_leader_idx]

3. 完整算法流程整合

将各阶段组合成完整的优化流程:

def optimize(self):
    for iter in range(self.max_iter):
        # 记录当前状态
        self.history['positions'].append(self.population.copy())
        self.history['fitness'].append(self.fitness.copy())
        self.history['leader_pos'].append(self.leader_pos.copy())
        
        # 执行优化步骤
        self.scout_phase()
        self.summon_phase()
        self.siege_phase()
        self.population_renew()
        
        # 打印进度
        if (iter+1) % 10 == 0:
            print(f"Iteration {iter+1}/{self.max_iter}, Best Fitness: {self.leader_fit:.4f}")
    
    return self.leader_pos, self.leader_fit

4. 可视化优化过程

创建动态可视化展示狼群优化过程:

def visualize_optimization(self, interval=200):
    fig, ax = plt.subplots(figsize=(10, 6))
    
    # 仅展示前两个维度(适用于二维问题)
    positions_history = np.array(self.history['positions'])
    leader_history = np.array(self.history['leader_pos'])
    
    # 创建散点图
    scatter = ax.scatter([], [], c='blue', alpha=0.6, label='Wolf Positions')
    leader_scatter = ax.scatter([], [], c='red', s=100, label='Leader')
    
    # 设置图形属性
    ax.set_xlim(self.lb[0], self.ub[0])
    ax.set_ylim(self.lb[1], self.ub[1])
    ax.set_xlabel('X1')
    ax.set_ylabel('X2')
    ax.set_title('Wolf Pack Algorithm Optimization Process')
    ax.legend()
    ax.grid(True)
    
    def update(frame):
        # 更新散点图数据
        current_pos = positions_history[frame]
        scatter.set_offsets(current_pos[:, :2])
        
        # 更新头狼位置
        current_leader = leader_history[frame]
        leader_scatter.set_offsets([current_leader[:2]])
        
        # 添加迭代信息
        ax.set_title(f'Wolf Pack Algorithm (Iteration {frame+1}/{self.max_iter})')
        return scatter, leader_scatter
    
    ani = FuncAnimation(fig, update, frames=len(positions_history),
                        interval=interval, blit=True)
    plt.close()
    return ani

5. 实际应用案例

5.1 测试函数优化

使用经典的Rastrigin函数进行测试:

def rastrigin(x):
    """Rastrigin测试函数"""
    A = 10
    return A * len(x) + np.sum(x**2 - A * np.cos(2 * np.pi * x))

# 参数设置
dim = 2
lb = np.array([-5.12] * dim)
ub = np.array([5.12] * dim)

# 创建优化器实例
wpa = WolfPackAlgorithm(rastrigin, dim, lb, ub, 
                       pop_size=30, max_iter=100,
                       alpha=0.8, beta=0.6, delta=0.8)

# 执行优化
best_solution, best_fitness = wpa.optimize()
print(f"Best Solution: {best_solution}")
print(f"Best Fitness: {best_fitness}")

# 可视化
ani = wpa.visualize_optimization()
from IPython.display import HTML
HTML(ani.to_jshtml())

5.2 参数调优技巧

狼群算法的性能很大程度上取决于参数设置。以下是关键参数的调优建议:

  1. 种群规模 (pop_size)

    • 一般设置在20-50之间
    • 复杂问题需要更大种群
    • 可通过网格搜索确定最优值
  2. 步长调节因子 (delta)

    • 影响算法的探索能力
    • 典型值范围:0.5-1.5
    • 可随迭代次数动态衰减:
      delta = delta_max - (delta_max-delta_min)*(iter/max_iter)
      
  3. 探狼比例因子 (alpha)

    • 控制探索与开发的平衡
    • 推荐范围:0.5-1.0
    • 值越大,探狼数量越少

参数组合效果对比:

参数组合 收敛速度 全局搜索能力 适用场景
大pop_size + 小delta 多峰复杂问题
小pop_size + 大delta 简单凸问题
动态delta + 适中alpha 中等 平衡 大多数问题

5.3 工程优化案例

考虑一个实际的机械设计优化问题:弹簧设计优化。目标是最小化弹簧重量,同时满足应力、挠度和几何约束。

问题建模:

def spring_design(x):
    """弹簧设计优化问题"""
    d = x[0]  # 钢丝直径
    D = x[1]  # 平均线圈直径
    N = x[2]  # 活动线圈数
    
    # 约束条件
    g1 = 1 - (D**3 * N)/(71785 * d**4)
    g2 = (4*D**2 - d*D)/(12566*(D*d**3 - d**4)) + 1/(5108*d**2) - 1
    g3 = 1 - (140.45*d)/(D**2*N)
    g4 = (D + d)/1.5 - 1
    
    # 惩罚项
    penalty = 0
    for g in [g1, g2, g3, g4]:
        if g > 0:
            penalty += 1e6 * g**2
    
    # 目标函数:弹簧重量
    return (N + 2) * D * d**2 + penalty

# 参数范围
lb = np.array([0.05, 0.25, 2.0])  # d, D, N的下界
ub = np.array([0.20, 1.30, 15.0]) # d, D, N的上界

# 优化执行
wpa = WolfPackAlgorithm(spring_design, dim=3, lb=lb, ub=ub,
                       pop_size=40, max_iter=200)
best_design, min_weight = wpa.optimize()

print(f"Optimal Design: d={best_design[0]:.4f}m, D={best_design[1]:.4f}m, N={best_design[2]:.2f}")
print(f"Minimum Weight: {min_weight:.4f} kg")

6. 算法改进与扩展

6.1 自适应步长策略

传统固定步长会影响算法性能,改进方案:

def adaptive_step(current_iter, max_iter):
    """自适应步长调整"""
    step_min = 0.1
    step_max = 1.0
    return step_max - (step_max-step_min)*(current_iter/max_iter)

# 在行为阶段调用
step_a = adaptive_step(iter, self.max_iter) * (self.ub-self.lb)/10

6.2 混合策略改进

结合其他算法的优势:

def hybrid_strategy(self):
    # 遗传算法交叉变异
    if np.random.rand() < 0.1:
        parent1, parent2 = np.random.choice(self.pop_size, 2, replace=False)
        crossover_point = np.random.randint(1, self.dim)
        child = np.concatenate([
            self.population[parent1][:crossover_point],
            self.population[parent2][crossover_point:]
        ])
        # 边界变异
        if np.random.rand() < 0.2:
            mutate_gene = np.random.randint(0, self.dim)
            child[mutate_gene] = np.random.uniform(self.lb[mutate_gene], self.ub[mutate_gene])
        
        child_fit = self.obj_func(child)
        # 替换最差个体
        worst_idx = np.argmax(self.fitness)
        if child_fit < self.fitness[worst_idx]:
            self.population[worst_idx] = child
            self.fitness[worst_idx] = child_fit

6.3 并行化实现

利用多核加速计算:

from multiprocessing import Pool

def parallel_evaluate(self, positions):
    """并行评估适应度"""
    with Pool() as pool:
        return np.array(pool.map(self.obj_func, positions))

# 替换原评估方式
self.fitness = self.parallel_evaluate(self.population)

实际项目中,根据问题复杂度选择合适的改进策略。对于简单问题,基础算法已足够;复杂多模态问题则需要混合策略。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐