多目标优化系列(六)SPEA

Multiobjective Evolutionary Algorithms: A Comparative Case Study and the Strength Pareto Approach

摘要

该算法有以下四个特点
a. 在第二个连续更新的种群中存储非支配解。(精英保留机制)
b. 根据支配其的非支配点的数量来评估个体的固定性
c. 使用帕累托优势关系来保留人口多样性。
d. 结合聚类程序以减少非支配解的集合而不破坏其特征。

简单总结一下,该算法主要在两个方便有所研究,(1) 每个个体的适应度求解方式,(2)使用聚类来减少多余点。
该文的主要研究在第五部分,如果想对其他算法有所了解请参考前面的章节,如果想直接了解该算法,可直接跳到第五部分,这里也是对该算法进行分析。

算法

该算法保留了其他多目标算法的特点:

  • 存储非支配解。

  • 用帕累托支配的概念来分配适应度。

  • 用聚类来减少非支配解的数目。

该算法与其他算法不同点:

  • 包含了上面三点(。。。)。

  • 适应度的分配仅依靠非支配解集,其他支配解互不相关。

  • 外部非支配解集合中的所有解都参与选择。

  • 为了保持多样性采用了一种新的小生境方式,这种方式不需要距离计算,是基于帕累托的。

算法步骤:

step1. 生成初始解P,建立一个空集合(精英解集合)P’。
step2. 复制P->P’。
step3. 从P’删除被其他个体支配的解。
step4. 如果P’ 中的解超过给定的最大值N’ ,用聚类方式修剪P’ 。
step5. 计算P’ 和P 中个体的适应值。
step6. 从P+P’中选出个体放到交配池(这里应该为P)中。
step7. 对交配池里面的元素进行杂交变异。
step8. 判断循环。

细节
  1. 是适应度分配方式:
    step1. 对P’ 中的元素i给定一个Si值(强度),Si与该点支配P集合里点的数目有关,设定n代表该点(P’中的非支配点)支配的点(在P中的点)的数目,N代表P集合中点的总数目。则Si= n/(N+1)。
    step2. P集合里的点的适应度等于P’中支配该点的非支配解的Si值相加+1。
    这里写图片描述

    用图来分析,先看a图,每个x点表示P’里的非支配解,实心原点表示P里面的支配解。最上面的支配解3/8是因为该点支配3个点,P’中的点个数是8。11/8是因为该点被右上角的x点支配,x点的Si值是3/8,3/8+1=11/8。其他值同样如此。
    这里写图片描述

  2. 聚类算法
    step1. 初始化聚类集合C,每一个P’中的点构建一个聚类集合。
    step2. 如果C里聚类的个数少于N’(给定的最大值),go step5。
    step3. 计算两个聚类c1,c2没对点间的距离。
    这里写图片描述
    step4. 选择最小的距离,合并这两个聚类。
    step5. 选取聚类中心(该聚类中聚其他点的平均距离最小)作为代表解。

  • 16
    点赞
  • 87
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
以下是spea2多目标优化的Python实现代码: ```python import random import copy class Individual: def __init__(self, num_objectives, chromosome_length, lower_bound, upper_bound): self.num_objectives = num_objectives self.chromosome_length = chromosome_length self.lower_bound = lower_bound self.upper_bound = upper_bound self.objectives = [0.0] * num_objectives self.dominated_by = [] self.dominating = 0 self.strength = 0 self.raw_fitness = 0 self.normalized_fitness = 0 self.chromosome = [random.uniform(lower_bound, upper_bound) for _ in range(chromosome_length)] def evaluate(self, objectives_functions): for i in range(self.num_objectives): self.objectives[i] = objectives_functions[i](self.chromosome) def dominates(self, other): for i in range(self.num_objectives): if self.objectives[i] > other.objectives[i]: return False return True def __eq__(self, other): return self.chromosome == other.chromosome def __str__(self): return f"chromosome: {self.chromosome}, objectives: {self.objectives}" class SPEA2: def __init__(self, num_objectives, chromosome_length, pop_size, archive_size, crossover_probability, mutation_probability, lower_bound, upper_bound, max_generations): self.num_objectives = num_objectives self.chromosome_length = chromosome_length self.pop_size = pop_size self.archive_size = archive_size self.crossover_probability = crossover_probability self.mutation_probability = mutation_probability self.lower_bound = lower_bound self.upper_bound = upper_bound self.max_generations = max_generations self.population = [Individual(num_objectives, chromosome_length, lower_bound, upper_bound) for _ in range(pop_size)] self.archive = [] def environmental_selection(self): for ind in self.population: ind.dominated_by = [] ind.dominating = 0 for i in range(len(self.archive)): for j in range(len(self.population)): if self.archive[i].dominates(self.population[j]): self.population[j].dominated_by.append(i) elif self.population[j].dominates(self.archive[i]): self.archive[i].dominating += 1 self.archive = [self.archive[i] for i in range(len(self.archive)) if self.archive[i].dominating < self.pop_size // 2] for ind in self.population: ind.strength = sum([self.archive[d].dominating for d in ind.dominated_by]) for ind in self.population: ind.raw_fitness = 1.0 / (ind.strength + 2.0) for ind in self.archive: ind.raw_fitness = sum([self.population[d].strength for d in ind.dominated_by]) ind.normalized_fitness = ind.raw_fitness / (len(self.population) + len(self.archive)) self.archive.sort(key=lambda ind: ind.normalized_fitness, reverse=True) self.archive = self.archive[:self.archive_size] def create_offspring(self): offspring = [] for i in range(self.pop_size): p1 = random.choice(self.archive) p2 = random.choice(self.archive) while p1 == p2: p2 = random.choice(self.archive) child = copy.deepcopy(p1) if random.random() < self.crossover_probability: for j in range(self.chromosome_length): if random.random() < 0.5: child.chromosome[j] = p2.chromosome[j] for j in range(self.chromosome_length): if random.random() < self.mutation_probability: child.chromosome[j] += random.gauss(0, 0.1) if child.chromosome[j] < self.lower_bound: child.chromosome[j] = self.lower_bound elif child.chromosome[j] > self.upper_bound: child.chromosome[j] = self.upper_bound offspring.append(child) return offspring def run(self, objectives_functions): for generation in range(self.max_generations): print(f"Generation {generation + 1}/{self.max_generations}") for ind in self.population: ind.evaluate(objectives_functions) self.archive += self.population self.environmental_selection() offspring = self.create_offspring() self.population = offspring ``` 这份代码实现了 SPEA2 算法,其中 `Individual` 类表示个体,包括染色体、对应的目标函数值、支配和被支配关系等信息;`SPEA2` 类则是算法的主体,包含了种群、非支配解集、交叉和变异概率、种群大小、迭代次数等参数,并实现了 SPEA2 算法的主要流程。在 `run` 方法中,我们需要传入一个目标函数列表 `objectives_functions`,它是一个长度为目标数的列表,其中每个元素是一个函数,用于计算某个个体的对应目标函数值。例如,如果我们要优化两个目标函数 $f_1(x)$ 和 $f_2(x)$,则 `objectives_functions` 可以定义为: ```python def f1(x): return x[0] ** 2 def f2(x): return (x[0] - 2) ** 2 objectives_functions = [f1, f2] ``` 在实际使用 SPEA2 算法时,我们可以根据具体问题来调整各参数的值,例如种群大小、迭代次数、交叉和变异概率等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值