R语言mco库nsga2优化报错:向量化目标函数返回矩阵格式异常
报错原因
- 核心原因和你的猜测一致:存在变量作用域问题。
n5、n6、n7是目标函数funct_set的内部局部变量,仅在目标函数调用时有效,约束函数gn作为独立的外部函数完全无法访问这三个变量。如果全局环境中存在同名变量,会导致gn返回错误的结果,进而引发维度匹配错误。 - 第二个原因是
nsga2默认启用向量化调用,每次会将整个种群(共100个个体,每个个体7个参数,组成7行100列的矩阵)传入目标函数和约束函数,但你的两个函数都是按照单个个体(输入为长度7的向量)编写的,运行时自然会出现维度不匹配的问题,你看到的「期望4行100列但得到7行100列」的报错就是该问题的直接表现。 - 第三个原因是上下界参数写法错误:
rep()函数的语法为rep(待重复值, 重复次数),你写的rep(80,80,80,80, 100,200,300)不符合语法要求,应该直接使用向量传入7个参数对应的上下界。
修复方案
- 首先关闭向量化调用,在
nsga2的参数中添加vectorized = FALSE,让算法每次仅传入单个个体的参数向量给目标函数和约束函数。 - 抽离公共计算逻辑,解决变量作用域问题:将目标函数中分箱、计算指标、统计分箱行数的逻辑抽为公共函数,目标函数和约束函数分别调用该公共函数获取需要的结果,避免跨函数访问局部变量。
- 修正约束函数的写法:
mco库要求约束返回值中所有值<=0时代表满足约束,不能直接返回逻辑值,需要将计数约束转换为数值型约束。 - 修正上下界参数的写法,直接用向量传入7个参数对应的上下限。
修复后的参考代码如下:
# 抽离公共计算逻辑 calc_f_and_counts <- function(x) { x1 <- x[1]; x2 <- x[2]; x3 <- x[3] ; x4 <- x[4]; x5 <- x[5]; x6 <- x[6]; x7 <- x[7] f <- numeric(4) train_data <- train_data %>% mutate(cat = ifelse(a1 <= x1 & b1 <= x3, "a", ifelse(a1 <= x2 & b1 <= x4, "b", "c"))) a_table = filter(train_data, cat == "a") b_table = filter(train_data, cat == "b") c_table = filter(train_data, cat == "c") table_a = mutate(a_table, quant = ifelse(c1 > x[5],1,0 )) table_b = mutate(b_table, quant = ifelse(c1 > x[6],1,0 )) table_c = mutate(c_table, quant = ifelse(c1 > x[7],1,0 )) f[1] = mean(table_a$quant) f[2] = mean(table_b$quant) f[3] = mean(table_c$quant) f[4] = mean(c(table_a$quant, table_b$quant, table_c$quant)) n5 = nrow(a_table) n6 = nrow(b_table) n7 = nrow(c_table) return(list(f = f, counts = c(n5, n6, n7))) } # 改写目标函数 funct_set <- function (x) { calc_f_and_counts(x)$f } # 改写约束函数 gn <- function(x) { counts = calc_f_and_counts(x)$counts n5 = counts[1]; n6 = counts[2]; n7 = counts[3] g1 <- x[3] - x[1] g2<- x[4] - x[2] g3 <- x[7] - x[6] g4 <- x[6] - x[5] # 约束转换:要求n>20对应20 - n <= 0,符合mco的约束规则 g5 <- 20 - n5 g6 <- 20 - n6 g7 <- 20 - n7 return(c(g1,g2,g3,g4, g5, g6, g7)) } # 修正后优化调用 optimization <- nsga2(funct_set, idim = 7, odim = 4 , constraints = gn, cdim = 7, generations=150, popsize=100, cprob=0.7, cdist=20, mprob=0.2, mdist=20, vectorized = FALSE, lower.bounds = c(80,80,80,80, 100,200,300), upper.bounds = c(120,120,120,120,200,300,400) )
内容的提问来源于stack exchange,提问作者stats_noob
相关产品推荐
相关产品推荐

