遗传算法(Genetic algorithm)求解one-max问题不收敛排查
遗传算法求解One-Max变体(全0个体)问题修复方案
已定位的问题点
- 语法错误:主循环中遍历种群计算适应度的
fits.append(fitness(k))行缺少缩进,代码无法正常执行 - 突变概率过高:当前配置下每个100位的个体每次迭代有超过99%的概率发生至少1次突变,优秀基因型极易被破坏,是适应度持续下降的核心原因
- 无精英保留机制:迭代过程中当代最优个体可能被选择、交叉、突变操作误删除,导致种群最优表现倒退
- 交叉点固定:固定在第50位切割交叉,降低了交叉操作的搜索多样性
- 个体列表是引用传递:选择操作返回的是原种群个体的引用,交叉突变时会直接修改原个体,可能导致重复修改的问题
修正后的完整代码
import random # 适应度计算不变,统计0的个数,全0得100分 def fitness(individual): return sum(1 for m in individual if m == 0) def selection(pop): chosen = [] for i in range(len(pop)): aspirants = [random.choice(pop) for _ in range(3)] # 按适应度降序排序取第一个,简化原有判断逻辑 macs = max(aspirants, key=fitness) # 深拷贝避免引用传递问题 chosen.append(macs.copy()) return chosen def crossover(offspring): for child1, child2 in zip(offspring[::2], offspring[1::2]): if random.random() < 0.7: # 改为随机交叉点 point = random.randint(1, len(child1)-1) child1[point:], child2[point:] = child2[point:], child1[point:] def mutate(offspring): for mut in offspring: # 降低每个个体的突变触发概率,同时降低位点突变概率 if random.random() < 0.1: for i in range(len(mut)): if random.random() < 0.01: mut[i] = 1 - mut[i] def gen_individ(): return [random.randint(0, 1) for _ in range(100)] def gen_pop(size=300): return [gen_individ() for _ in range(size)] if __name__ == "__main__": g = 0 popul = gen_pop() print(f"length of pop = {len(popul)}") fits = [fitness(k) for k in popul] print(f"best fitness before = {max(fits)}") while max(fits) < 100 and g < 100: g += 1 # 精英保留:先保存当代最优个体 elite_idx = fits.index(max(fits)) elite = popul[elite_idx].copy() # 生成后代 offspring = selection(popul) crossover(offspring) mutate(offspring) # 替换最差的个体为精英,保证最优不丢失 offspring_fits = [fitness(i) for i in offspring] worst_idx = offspring_fits.index(min(offspring_fits)) offspring[worst_idx] = elite # 更新种群 popul = offspring fits = [fitness(k) for k in popul] print(f"length of pop = {len(popul)}") print(f"best fitness after = {max(fits)}") print(f"generation : {g}")
修改说明
- 补全了缩进错误,同时简化了部分冗余代码的写法,核心逻辑保持不变
- 调整突变概率:个体突变触发概率从0.3降到0.1,位点突变概率从0.05降到0.01,避免破坏优秀基因型
- 增加精英保留机制:每轮迭代将当代最优个体直接替换到后代种群的最差位置,保证种群最优适应度不会下降
- 将固定交叉点改为随机交叉点,提升搜索多样性
- 选择时增加个体拷贝,避免引用传递导致的同个个体被多次修改的问题
修改后的代码正常运行后一般在30代以内就能收敛到全0个体,不会再出现适应度持续下降的问题。
内容的提问来源于stack exchange,提问作者kara.aimen
相关产品推荐
相关产品推荐

