我正在尝试在python中实现遗传算法。 我最初的人口是六个人。我测量它们的适应性和进入下一代的概率,并选择三对交配,交配概率为 0.7。为了进行交叉,我将配对和交配概率传递给一个函数。
new_population = cross_over(pairsg, mating_prob)
其中pairsg是选择用于交配的对,而mateing-prob是一个二进制列表(如果 1 个cross_over,如果 0 个不(。问题是cross_over函数会改变原始总体,尽管内部从未使用过总体变量
def cross_over(prs, mp):
new = []
for pr in prs:
if mp[prs.index(pr)] == 1:
index = np.random.choice([1,2,3], p=[1/3, 1/3, 1/3])
pr[0][:index], pr[1][:index] = pr[1][:index], pr[0][:index]
for pr in prs:
new.append(pr[0])
new.append(pr[1])
return new
这是完整的代码:
from random import *
import numpy as np
#fitness function
def fit(x):
return 15*x -x**2
#covert binary list to decimal number
def to_dec(x):
return int("".join(str(e) for e in x), 2)
#picks pairs from the original population
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])
pairsl.append(pair)
return pairsl
#mating function
def cross_over(prs, mp):
new = []
for pr in prs:
if mp[prs.index(pr)] == 1:
index = np.random.choice([1,2,3], p=[1/3, 1/3, 1/3])
pr[0][:index], pr[1][:index] = pr[1][:index], pr[0][:index]
for pr in prs:
new.append(pr[0])
new.append(pr[1])
return new
population = [[1,0,1,0], [0,1,1,0], [1,0,0,1], [1,1,1,0],[1,1,0,0],[1,0,0,0]]
fittness = [fit(to_dec(y)) for y in population]
s = sum(fittness)
prob = [e/s for e in fittness]
pairsg = gen_pairs(population.copy(), prob)
mating_prob = []
for i in pairsg:
mating_prob.append(np.random.choice([0,1], p=[0.3,0.7]))
new_population = cross_over(pairsg, mating_prob)
问题是你正在做一个copy
gen_pairs(population.copy(), prob)
但是您复制外部列表,但不复制子列表数据(它是浅表副本(。所以
pr[0][:index], pr[1][:index] = pr[1][:index], pr[0][:index]
更改原始数据(因为pair.append(populationl[temp])
也不会复制而是使用相同的子列表引用(
您必须按照子列表的引用来弄清楚这一点。
一旦你理解了这个问题,有很多方法可以避免这种情况。在某个时候复制子列表。
你可以做:
gen_pairs([x.copy() for x in population], prob)
创建"深拷贝"(或copy.deepcopy(population))
(
或替换
pair.append(populationl[temp])
由
pair.append(populationl[temp].copy())
每当将参数传递给 python 函数时,基本上只需传递对该对象的引用,并且您对函数内部对象所做的一切也会反映在外部。即使对象在外面有不同的名称,也会发生这种情况。pairsg
和prs
仍然引用同一个列表。这类似于在a = []
和b = a
之后,a
和b
都指完全相同的物体。
因此,在将可变参数(例如列表(传递给函数时要小心。参数传递对于不可变参数的工作方式相同,但您不会遇到此问题,因为无法更改不可变参数。
所以解决方案是不修改 prs。这应该有效:
def cross_over(prs, mp):
new = []
for pr in prs:
if mp[prs.index(pr)] == 1:
index = np.random.choice([1,2,3], p=[1/3, 1/3, 1/3])
new.append(pr[1][:index])
new.append(pr[0][:index])
else:
new.append(pr[0])
new.append(pr[1])
return new