matlab实现NSGA-II(带精英策略的非支配排序遗传算法)

NSGA-II(带精英策略的非支配排序遗传算法)是多目标优化领域的经典算法,特别适合在MATLAB中实现。

NSGA-II 核心原理

NSGA-II的核心在于其高效解决多目标优化问题的机制:

  1. 非支配排序:将种群分成不同层级(Pareto等级),优先选择层级高的解。
  2. 拥挤度距离:在同一层级内,选择分布更分散的解以保持多样性。
  3. 精英策略:保留父代中的优秀个体直接进入子代。

MATLAB实现方案对比

在MATLAB中实现NSGA-II,主要有三种途径,各有优劣:

实现方式 核心工具/来源 优点 缺点 适合场景
自定义编程 完全手写代码 理解深入,完全可控,可高度定制 开发时间长,需要扎实编程基础 学习算法原理、特定问题研究
优化工具箱 gamultiobj函数 官方支持,稳定可靠,调用简单 "黑箱"操作,自定义程度有限 快速解决标准多目标问题
社区代码 File Exchange开源代码 有现成参考,质量较高 需理解他人代码,可能与需求不完全匹配 快速上手,适度修改使用

自定义NSGA-II实现框架

1. 主函数结构

matlab 复制代码
function [pop, front] = NSGA2(params)
    % 初始化种群
    pop = initializePopulation(params);
    
    % 主循环
    for gen = 1:params.maxGen
        % 评估目标函数值
        pop = evaluatePopulation(pop, params);
        
        % 非支配排序与拥挤度计算
        [pop, front] = nonDominatedSort(pop);
        pop = crowdingDistance(pop, front);
        
        % 选择、交叉、变异生成子代
        offspring = generateOffspring(pop, params);
        offspring = evaluatePopulation(offspring, params);
        
        % 合并父代与子代,进行环境选择
        combinedPop = [pop, offspring];
        [combinedPop, ~] = nonDominatedSort(combinedPop);
        combinedPop = crowdingDistance(combinedPop, front);
        
        % 选择新一代种群
        pop = environmentalSelection(combinedPop, params.popSize);
        
        % 输出当前代信息
        fprintf('Generation %d: %d Pareto solutions\n', gen, length(front{1}));
    end
end

2. 关键操作实现

非支配排序与拥挤度计算

matlab 复制代码
function [pop, front] = nonDominatedSort(pop)
    % 实现快速非支配排序
    nPop = length(pop);
    
    % 初始化支配关系
    for i = 1:nPop
        pop(i).dominanceCount = 0;
        pop(i).dominatedSet = [];
    end
    
    % 比较每对个体
    for i = 1:nPop
        for j = i+1:nPop
            % 比较支配关系
            if dominates(pop(i).obj, pop(j).obj)
                pop(i).dominatedSet = [pop(i).dominatedSet, j];
                pop(j).dominanceCount = pop(j).dominanceCount + 1;
            elseif dominates(pop(j).obj, pop(i).obj)
                pop(j).dominatedSet = [pop(j).dominatedSet, i];
                pop(i).dominanceCount = pop(i).dominanceCount + 1;
            end
        end
    end
    
    % 分层
    front = {};
    currentFront = find([pop.dominanceCount] == 0);
    while ~isempty(currentFront)
        front{end+1} = currentFront;
        nextFront = [];
        for i = currentFront
            for j = pop(i).dominatedSet
                pop(j).dominanceCount = pop(j).dominanceCount - 1;
                if pop(j).dominanceCount == 0
                    nextFront = [nextFront, j];
                end
            end
        end
        currentFront = nextFront;
    end
end

function pop = crowdingDistance(pop, front)
    % 计算拥挤度距离
    nObj = size(pop(1).obj, 2);
    
    for f = 1:length(front)
        currentFront = front{f};
        nCurrent = length(currentFront);
        
        if nCurrent <= 2
            [pop(currentFront).crowdingDistance] = deal(inf);
            continue;
        end
        
        % 初始化拥挤度
        for i = currentFront
            pop(i).crowdingDistance = 0;
        end
        
        % 对每个目标计算
        for m = 1:nObj
            % 按目标值排序
            [~, order] = sort([pop(currentFront).obj(m)]);
            sortedFront = currentFront(order);
            
            % 边界个体有无限拥挤度
            pop(sortedFront(1)).crowdingDistance = inf;
            pop(sortedFront(end)).crowdingDistance = inf;
            
            % 计算中间个体的拥挤度
            fmax = pop(sortedFront(end)).obj(m);
            fmin = pop(sortedFront(1)).obj(m);
            
            if (fmax - fmin) > eps
                for i = 2:nCurrent-1
                    pop(sortedFront(i)).crowdingDistance = ...
                        pop(sortedFront(i)).crowdingDistance + ...
                        (pop(sortedFront(i+1)).obj(m) - pop(sortedFront(i-1)).obj(m)) / (fmax - fmin);
                end
            end
        end
    end
end

3. 使用MATLAB内置函数

如果你不想完全从头实现,MATLAB的Global Optimization Toolbox提供了内置的多目标遗传算法:

matlab 复制代码
% 定义多目标函数(以ZDT1测试问题为例)
function f = zdt1(x)
    n = length(x);
    f1 = x(1);
    g = 1 + 9 * sum(x(2:end)) / (n-1);
    h = 1 - sqrt(f1 / g);
    f2 = g * h;
    f = [f1, f2];
end

% 使用gamultiobj求解
options = optimoptions('gamultiobj', ...
    'PopulationSize', 100, ...
    'MaxGenerations', 200, ...
    'ParetoFraction', 0.35, ...
    'PlotFcn', @gaplotpareto);

nvars = 30; % 变量维度
lb = zeros(1, nvars); % 下界
ub = ones(1, nvars); % 上界

[x, fval] = gamultiobj(@zdt1, nvars, [], [], [], [], lb, ub, options);

% 绘制Pareto前沿
figure;
plot(fval(:,1), fval(:,2), 'o');
xlabel('f_1');
ylabel('f_2');
title('Pareto Front obtained by gamultiobj');
grid on;

算法参数

参数 建议值 说明
种群大小 50-200 问题复杂则取大值
最大代数 100-500 根据收敛情况调整
交叉概率 0.7-0.9 模拟二进制交叉(SBX)常用
变异概率 1/n n为变量维度
分布指数 20 (交叉), 20 (变异) 控制交叉/变异操作的分布

参考代码 基于matlab的NSGA-II算法 www.3dddown.com/csa/96073.html

推荐资源

  1. 原始论文:Deb, K., et al. (2002). "A fast and elitist multiobjective genetic algorithm: NSGA-II"
  2. MATLAB File Exchange:搜索"NSGA-II"可找到多个高质量实现
  3. 书籍:《Multi-Objective Optimization Using Evolutionary Algorithms》by Kalyanmoy Deb
相关推荐
乐迪信息8 小时前
乐迪信息:智能识别船舶种类的AI解决方案
大数据·网络·人工智能·算法·无人机
朔北之忘 Clancy8 小时前
第一章 顺序结构程序设计(1)
c++·算法·青少年编程·竞赛·教材·考级·讲义
老鼠只爱大米8 小时前
LeetCode经典算法面试题 #41:缺失的第一个正数(位置交换法、标记法等多种方法详解)
算法·leetcode·原地哈希·缺失的第一个正数·算法面试·位图法·集合哈希法
hetao17338378 小时前
2026-01-14~15 hetao1733837 的刷题笔记
c++·笔记·算法
百度搜不到…8 小时前
背包问题递推公式中的dp[j-nums[j]]到底怎么理解
算法·leetcode·动态规划·背包问题
一起养小猫8 小时前
LeetCode100天Day13-移除元素与多数元素
java·算法·leetcode
ACERT3339 小时前
10.吴恩达机器学习——无监督学习01聚类与异常检测算法
python·算法·机器学习
诗词在线9 小时前
从算法重构到场景复用:古诗词数字化的技术破局与落地实践
python·算法·重构
不穿格子的程序员9 小时前
从零开始写算法——二叉树篇7:从前序与中序遍历序列构造二叉树 + 二叉树的最近公共祖先
数据结构·算法