Python遗传算法中cross_over函数意外修改原始种群问题排查
问题分析与解决方案:遗传算法中原始种群被意外修改
嘿,这个问题我太熟了——本质是Python里列表的引用传递和浅拷贝特性在搞鬼!虽然你在调用gen_pairs时用了population.copy(),但这个操作只是做了浅拷贝:它复制了顶层的列表容器,但里面的每个二进制子列表(也就是种群里的个体)仍然是指向原始population中对应元素的引用,并没有真正生成独立的副本。
咱们捋一遍问题的发生路径:
- 在
gen_pairs函数里,你通过pair.append(populationl[temp])把浅拷贝后的列表元素加入配对,但这些元素和原始种群里的个体是同一个对象; - 到了
cross_over函数,当你执行pr[0][:index], pr[1][:index] = pr[1][:index], pr[0][:index]时,你直接修改了这些引用指向的原始列表内容——相当于绕了个弯子修改了原始种群,哪怕你没直接传population变量进去。
另外还有个小坑:你用prs.index(pr)来获取配对的索引,如果出现重复的配对(比如同一个个体被选中多次),index()只会返回第一个匹配项的位置,导致mp的概率对应错误,建议用enumerate来遍历索引更可靠。
解决方案:操作个体的副本而非原始引用
有两种简单的修复方式,选哪种都可以:
方法1:生成配对时就创建个体的副本
修改gen_pairs函数,在添加个体到配对时,对子列表做拷贝,确保每个配对里的个体都是独立的副本:
def gen_pairs(populationl, prob): pairsl = [] test = [0, 1, 2, 3, 4, 5] for i in range(3): pair = [] for j in range(2): temp = np.random.choice(test, p=prob) # 对每个个体子列表做拷贝,生成独立副本 pair.append(populationl[temp].copy()) pairsl.append(pair) return pairsl
方法2:在交叉操作前创建个体副本
如果你不想修改gen_pairs,可以在cross_over里操作前先复制个体,避免触碰原始引用:
def cross_over(prs, mp): new = [] # 用enumerate获取索引,避免prs.index(pr)的索引错误问题 for idx, pr in enumerate(prs): if mp[idx] == 1: index = np.random.choice([1,2,3], p=[1/3, 1/3, 1/3]) # 创建两个个体的独立副本 ind1 = pr[0].copy() ind2 = pr[1].copy() # 对副本执行交叉操作 ind1[:index], ind2[:index] = ind2[:index], ind1[:index] new.append(ind1) new.append(ind2) else: # 不交叉时也添加副本,保证新种群和原始种群完全独立 new.append(pr[0].copy()) new.append(pr[1].copy()) return new
这两种方法都能确保交叉操作只作用于新的个体副本,不会影响原始的population变量。
内容的提问来源于stack exchange,提问作者Mohammad Nur
相关产品推荐
相关产品推荐

