Python实现MATLAB repmat功能创建Rabbits变量的正确方法
Python复现MOHHO算法时Rabbits变量构建问题
问题背景
需要转写的MATLAB代码来自MathWorks文件交换平台开源多目标哈里斯鹰优化(MOHHO)项目的Main_MOHHO.m文件,项目地址:多目标哈里斯鹰优化MOHHO项目。使用Python复现代码时,无法正确构建Rabbits变量。
原MATLAB初始化代码
clc; clear; close all; %% Problem Definition nVar=3; % Number of Decision Variables VarSize=[1 nVar]; % Size of Decision Variables Matrix VarMin=0; % Lower Bound of Variables VarMax=1; % Upper Bound of Variables nPop=5; % Population Size %% Initialization empty_Rabbit.Location=[]; empty_Rabbit.Cost=[]; empty_Rabbit.Sol=[]; empty_Rabbit.IsDominated=[]; empty_Rabbit.GridIndex=[]; empty_Rabbit.GridSubIndex=[]; Rabbits=repmat(empty_Rabbit,nPop,1); for i=1:nPop Rabbits(i).Location = rand(VarSize).*(VarMax-VarMin)+VarMin; X(i,:) = rand(VarSize).*(VarMax-VarMin)+VarMin; end
复现问题表现
初始编写的Python代码运行后,所有行的Location属性值完全相同,和MATLAB运行得到的每个个体独立随机位置的结果不符。
初始错误Python代码如下:
import numpy as np nVar = 3 # Number of Decision Variables VarSize = np.array((1, nVar)) # Size of Decision Variables Matrix VarMin = 0 # Lower Bound of Variables VarMax = 1 # Upper Bound of Variables nPop = 5 # Population Size class empty_Rabbit: Location = [] Cost = [] IsDominated = [] GridIndex = [] GridSubIndex = [] Sol = [] Rabbits = np.tile(empty_Rabbit, (nPop, 1)) X = np.zeros((nPop, nVar)) Rabbit_Location = np.zeros((VarSize)) Rabbit_Energy = math.inf for i in range(nPop): Rabbits[i, 0].Location = np.multiply(np.random.rand(VarSize[0], VarSize[1]), (VarMax-VarMin) + VarMin) print(Rabbits[i,0].Location)
错误原因
- 使用
np.tile复制自定义类对象时,复制的全是同一个类的引用,numpy数组中所有位置指向的都是同一个类对象,修改任意位置的属性本质都是修改同一个对象的属性,自然所有元素的属性值都会同步为最后一次赋值的结果 - 类属性直接定义在类体中,所有实例会共享该属性,没有定义为每个实例独有的实例属性
- 随机位置生成逻辑存在括号错误,
(VarMax-VarMin) + VarMin的写法完全不符合区间随机数的计算逻辑
正确实现方法
不需要强行用np.tile复刻MATLAB的结构体数组复制逻辑,Python中直接通过列表推导式循环创建独立的类实例即可,类的属性要定义在__init__实例方法中,保证每个实例的属性相互独立。
修正后的可运行代码:
import numpy as np import math nVar = 3 # 决策变量数量 VarSize = (1, nVar) # 决策变量矩阵维度 VarMin = 0 # 变量下界 VarMax = 1 # 变量上界 nPop = 5 # 种群规模 # 定义Rabbit类,所有属性为实例独有属性 class Rabbit: def __init__(self): self.Location = [] self.Cost = [] self.Sol = [] self.IsDominated = [] self.GridIndex = [] self.GridSubIndex = [] # 循环生成独立实例,实现和MATLAB repmat(empty_Rabbit,nPop,1)一致的效果 Rabbits = [Rabbit() for _ in range(nPop)] X = np.zeros((nPop, nVar)) Rabbit_Location = np.zeros(VarSize) Rabbit_Energy = math.inf for i in range(nPop): # 生成[VarMin, VarMax]区间内的随机位置 rand_pos = np.random.rand(VarSize[0], VarSize[1]) * (VarMax - VarMin) + VarMin Rabbits[i].Location = rand_pos X[i, :] = rand_pos print(f"第{i+1}个个体位置:{Rabbits[i].Location}")
实现说明
- 自定义对象存储使用普通Python列表即可,不需要转为numpy数组,访问时直接通过
Rabbits[i]索引对应个体,和MATLAB结构体数组访问逻辑一致 - 所有个体实例都是独立创建的对象,修改任意个体的属性不会影响其他个体
- 修正了随机数生成的计算逻辑,保证生成的位置在设定的变量上下界范围内
内容的提问来源于stack exchange,提问作者Rona Freya
相关产品推荐
相关产品推荐

