NSGA-II:快速非支配排序遗传算法

NSGA-II:快速非支配排序遗传算法(Fast Elitist Non-Dominated Sorting Genetic Algorithm)

在多目标优化(Multi-Objective Optimization, MOO)中,我们通常希望同时优化多个相互冲突的目标,而不是简单地找到一个最优解。NSGA-II(Non-dominated Sorting Genetic Algorithm II,快速非支配排序遗传算法 II)是一种强大的多目标优化算法,广泛应用于工程、金融、人工智能等领域。

1. NSGA-II 的核心思想

NSGA-II 是 Deb 等人在 2002 年提出的一种改进的遗传算法(GA),其核心思想包括:

  • 非支配排序(Non-dominated Sorting):对种群进行排序,优先保留Pareto 最优解
  • 拥挤度计算(Crowding Distance Calculation):在相同支配层次(front)的个体中,选择分布均匀的解。
  • 精英保留策略(Elitism):下一代种群不仅包括子代,还包括当前种群中最优的个体。

2. 数学原理

2.1 Pareto 最优解

一个解 x x x 被称为 Pareto 最优解,如果不存在另一个解 y y y 满足:
∀ i , f i ( y ) ≤ f i ( x ) 且 ∃ j , f j ( y ) < f j ( x ) \forall i, f_i(y) \leq f_i(x) \quad \text{且} \quad \exists j, f_j(y) < f_j(x) i,fi(y)fi(x)j,fj(y)<fj(x)
其中 f i ( x ) f_i(x) fi(x) 代表目标函数值。

Pareto 前沿(Pareto Front) 由所有 Pareto 最优解组成的集合形成。

2.2 非支配排序

定义种群中的每个个体 x x x支配度(dominance count) n x n_x nx,表示支配它的个体数量。然后进行层级划分:

  1. 第一层 Pareto 前沿(Front 1) n x = 0 n_x = 0 nx=0 的个体。
  2. 第二层 Pareto 前沿(Front 2):仅被 Front 1 个体支配的个体。
  3. 依次递推,直到所有个体被分类。

2.3 拥挤度计算(Crowding Distance)

拥挤度衡量了解在 Pareto 前沿上的分布情况:
C D ( i ) = ∑ m = 1 M ( f m i + 1 − f m i − 1 f m max ⁡ − f m min ⁡ ) CD(i) = \sum_{m=1}^{M} \left( \frac{f_m^{i+1} - f_m^{i-1}}{f_m^{\max} - f_m^{\min}} \right) CD(i)=m=1M(fmmaxfmminfmi+1fmi1)
其中, f m i f_m^i fmi 代表目标函数 f m f_m fm 的第 i i i 个个体, f m max ⁡ f_m^{\max} fmmax f m min ⁡ f_m^{\min} fmmin 分别为该目标的最大值和最小值。

3. NSGA-II 的实现步骤

Step 1:初始化种群

随机生成一组个体,每个个体代表一个可能的解。

Step 2:非支配排序(Non-dominated Sorting)

NSGA-II 采用快速非支配排序方法,将种群划分为多个非支配层(Fronts):

  • 第一层包含所有非支配解。
  • 第二层包含被第一层支配但不被彼此支配的解。
  • 依次类推,直到所有个体都被分类。

Step 3:计算拥挤距离(Crowding Distance)

为了保持 Pareto 前沿的均匀分布,NSGA-II 计算个体的拥挤距离(Crowding Distance):

  • 拥挤距离衡量了一个解与其他解之间的间隔。
  • 距离大的个体优先保留,以确保解的多样性。

Step 4:选择(Selection)

  • 采用 锦标赛选择(Tournament Selection),优先选择非支配层级更低或拥挤距离更大的个体。

Step 5:交叉(Crossover)与变异(Mutation)

  • 交叉:使用模拟二进制交叉(SBX, Simulated Binary Crossover)生成新个体。
  • 变异:采用多项式变异(Polynomial Mutation)增加解的多样性。

Step 6:生成下一代(Next Generation)

  • 结合当前种群和子代种群。
  • 进行非支配排序按 Pareto 层级和拥挤度选择个体,形成下一代。
  • 迭代至最大代数。

示例问题

假设我们有两个目标函数:
f 1 ( x ) = x 2 f_1(x) = x^2 f1(x)=x2
f 2 ( x ) = ( x − 2 ) 2 f_2(x) = (x - 2)^2 f2(x)=(x2)2
目标是同时最小化 f 1 f_1 f1 f 2 f_2 f2

4. Python 代码示例

使用 DEAP(Distributed Evolutionary Algorithms in Python)实现 NSGA-II 解决上述示例问题。

import random
import numpy as np
from deap import base, creator, tools, algorithms
import matplotlib.pyplot as plt

# 定义多目标优化问题(最小化)
creator.create("FitnessMulti", base.Fitness, weights=(-1.0, -1.0))  # 最小化两个目标
creator.create("Individual", list, fitness=creator.FitnessMulti)

# 初始化种群
toolbox = base.Toolbox()
toolbox.register("attr_float", random.uniform, -10, 10)
toolbox.register("individual", tools.initRepeat, creator.Individual, toolbox.attr_float, n=1)
toolbox.register("population", tools.initRepeat, list, toolbox.individual)

def evaluate(individual):
    x = individual[0]
    return x**2, (x - 2)**2  # 目标函数 f1(x), f2(x)

toolbox.register("mate", tools.cxBlend, alpha=0.5)
toolbox.register("mutate", tools.mutGaussian, mu=0, sigma=1, indpb=0.2)
toolbox.register("select", tools.selNSGA2)
toolbox.register("evaluate", evaluate)

def main():
    pop_size = 100  # 种群大小
    generations = 100  # 迭代次数
    pop = toolbox.population(n=pop_size)

    stats = tools.Statistics(lambda ind: ind.fitness.values)
    stats.register("min", np.min)
    stats.register("max", np.max)

    pop, logbook = algorithms.eaMuPlusLambda(pop, toolbox, mu=pop_size, lambda_=pop_size,
                                              cxpb=0.7, mutpb=0.2, ngen=generations,
                                              stats=stats, halloffame=None, verbose=True)
    return pop

if __name__ == "__main__":
    pop = main()
    
    # 获取 Pareto 前沿解
    pareto_front = np.array([ind.fitness.values for ind in pop])
    
    # 可视化 Pareto 前沿
    plt.scatter(pareto_front[:, 0], pareto_front[:, 1], c='b', label='Pareto Front')
    plt.xlabel("f1(x) = x^2")
    plt.ylabel("f2(x) = (x - 2)^2")
    plt.legend()
    plt.title("NSGA-II Pareto Front")
    plt.show()

5. 结果与分析

运行上述代码后,我们得到一个 Pareto 前沿图,其中每个点都是 NSGA-II 发现的 Pareto 最优解。通过观察该图,我们可以直观地看到优化的权衡关系
在这里插入图片描述

6. NSGA-II 的优势

能够高效搜索 Pareto 前沿,适用于高维多目标优化。
保持解的多样性,通过拥挤距离防止收敛到局部最优。
无需目标加权,适用于权衡关系不明确的问题。

### Redis 中 Hash 操作的方法和属性 在 Spring Data Redis 中,`RedisTemplate` 提供了 `opsForHash()` 方法来执行针对哈希表的操作。以下是常用的几种方法及其功能: #### 基本操作 - **存储键值对** 使用 `put(K key, HK hashKey, HV value)` 可以向指定的哈希表中存入一个字段和对应的值。 ```java redisTemplate.opsForHash().put("hash-key", "field1", "value1"); ``` - **批量存储多个键值对** 利用 `putAll(K key, Map<HK, HV> m)` 能够一次性将多组键值对加入到同一个哈希表里[^1]。 ```java Map<String, String> map = new HashMap<>(); map.put("field2", "value2"); map.put("field3", "value3"); redisTemplate.opsForHash().putAll("hash-key", map); ``` - **删除特定字段** 执行 `delete(K key, Object... hashKeys)` 来移除某个或某些已存在的字段。 ```java redisTemplate.opsForHash().delete("hash-key", "field1", "field2"); ``` #### 查询操作 - **获取单个字段的值** 应用 `get(Object key, Object hashKey)` 获取对应于给定字段名的数据项。 ```java Object fieldValue = redisTemplate.opsForHash().get("hash-key", "field3"); System.out.println(fieldValue); ``` - **检索整个哈希表的内容** 函数 `entries(K key)` 返回的是包含所有字段名称及相应值得映射关系的对象集合。 ```java Map<Object, Object> entries = redisTemplate.opsForHash().entries("hash-key"); for (Entry<Object, Object> entry : entries.entrySet()) { System.out.println(entry.getKey() + ": " + entry.getValue()); } ``` - **查询全部字段的名字列表** 方式 `keys(K key)` 将返回该哈希结构下所有的字段标识符组成的集合作为结果。 ```java Set<Object> keys = redisTemplate.opsForHash().keys("hash-key"); System.out.println(keys); ``` - **取得某字段的数量统计** 功能 `size(K key)` 计算并给出当前哈希内所含有的条目总数。 ```java Long size = redisTemplate.opsForHash().size("hash-key"); System.out.println(size); ``` #### 更新与增量操作 - **原子增加数值型字段** 对整数类型的成员变量应用 `increment(K key, HK hashKey, long delta)` 或者浮点数版本 `increment(K key, HK hashKey, double delta)` 实现安全可靠的加法运算。 ```java // 整形递增 redisTemplate.opsForHash().increment("counter-hash", "count-field", 1L); // 浮点数递增 redisTemplate.opsForHash().increment("float-counter-hash", "float-count-field", 0.5D); ``` 这些 API 接口提供了丰富的手段用于管理和访问 Redis 的哈希数据类型,使得开发者可以方便快捷地完成各种业务逻辑需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值