如何使用DEAP库获取遗传算法的所有可行解
基于DEAP的约束满足型遗传算法饮食方案生成问题解答
约束处理与不可行解过滤
你之前使用的tools.DeltaPenalty属于软惩罚机制,核心作用是给不可行解赋予极低适应度,让其在选择阶段更容易被淘汰,并不会直接将不可行解移出种群,因此测试时看到违反约束的个体残留是正常现象。如果需要严格过滤不可行解,可选择以下两种实现方案:
- 方案1:将可行性校验直接写入评估函数
这种方式逻辑最可控,不需要额外依赖装饰器,只有通过约束校验的个体才会计算真实适应度,未通过的个体直接返回最差适应度值,示例代码如下:def evaluate(individual): # 先计算各营养指标总和 total_kcal = sum(x * y for x, y in zip(kcal_data, individual)) total_prot = sum(x * y for x, y in zip(prot_data, individual)) # 补全所有营养约束规则 is_feasible = ( 7 * 1999 < total_kcal < 7 * 2001 and 7 * 60.5 < total_prot # 其余脂肪、碳水、微量元素等约束按相同格式补充 ) if not is_feasible: # 返回预设的最差适应度,单目标优化返回单元素元组,多目标对应返回等长元组 return (9999,) # 仅对可行解执行正常适应度计算,例如计算与目标营养值的偏差、食材成本、饮食多样性得分等 fitness = # 自定义适应度计算逻辑 return (fitness,) - 方案2:进化流程中硬删除不可行解
如果完全不希望不可行解参与后续交叉、变异流程,可以在每一代种群生成(交叉、变异操作完成)后,遍历所有个体删除未通过可行性校验的个体,再从当前代已有的可行解中随机复制、或重新生成新的随机个体,将种群规模补全到预设值即可。注意不要删除后直接进入下一代,否则种群规模会逐代缩减,最终导致算法提前收敛失效。提示:如果你的营养约束阈值比较严格,硬删除方案容易出现进化初期可行解数量不足、收敛速度慢的问题,优先选择写入评估函数的软过滤方案更稳妥。
全世代可行个体的存储与访问
DEAP内置的标准进化算法(如eaSimple)默认仅返回最终代种群,要获取全流程生成的所有可行解(包括非最优解),不需要修改框架源码,只需自行添加存储逻辑即可:
- 第一步:初始化全局存储容器,推荐用带自动去重能力的集合存储,避免重复记录基因型完全一致的个体;如果需要按世代归档,可改用字典结构,key为世代编号,value为对应世代的可行解列表。
# 存储格式:(个体基因型元组, 对应适应度值) all_feasible_solutions = set() - 第二步:将存储逻辑嵌入评估函数(覆盖率最高,不会漏掉任何新生成的个体):只要个体通过可行性校验,就先存入容器再返回适应度值,修改后的评估函数示例如下:
def evaluate(individual): total_kcal = sum(x * y for x, y in zip(kcal_data, individual)) total_prot = sum(x * y for x, y in zip(prot_data, individual)) is_feasible = ( 7 * 1999 < total_kcal < 7 * 2001 and 7 * 60.5 < total_prot # 补全其余约束 ) if not is_feasible: return (9999,) fitness = # 自定义适应度计算逻辑 # 列表类型的个体不能存入集合,转成不可变的元组类型做去重判断 ind_key = tuple(individual) if ind_key not in [item[0] for item in all_feasible_solutions]: all_feasible_solutions.add( (ind_key, fitness) ) return (fitness,) - 算法运行结束后,直接读取
all_feasible_solutions即可拿到所有生成过的可行解,你可以根据适应度分层抽样,筛选出多样化的符合要求的饮食方案,不需要局限于最终种群的最优个体。
优化小技巧:如果约束严格,建议初始种群生成阶段就加入可行性校验,先生成一批满足约束的个体作为初代,能大幅降低前期不可行解占比,加快收敛速度。
内容的提问来源于stack exchange,提问作者Caroline Herlev Gebara
相关产品推荐
相关产品推荐

