我正在尝试用Python编写遗传算法框架,并且遇到了浅/深复制的问题。我的背景主要是C / C ++,我很难理解这些连接是如何持续存在的。
我所看到的是子类中属性列表的长度爆炸。我的代码如下......我会指出问题。
这是单个基因的类。本质上,它应该有一个名称,值和布尔标志。 Gene
的实例填充了Individual
类中的列表。
# gene class
class Gene():
# constructor
def __init__(self, name, is_float):
self.name_ = name
self.is_float_ = is_float
self.value_ = self.randomize_gene()
# create a random gene
def randomize_gene(self):
return random.random()
这是我的Individual
课程。每一代,都会创建这些代码(我将在类声明后显示创建代码)并应用典型的遗传算法操作。值得注意的是print len(self.Genes_)
调用,每次实例化此类时都会增长。
# individual class
class Individual():
# genome definition
Genes_ = [] # genes list
evaluated_ = False # prevent re-evaluation
fitness_ = 0.0 # fitness value (from evaluation)
trace_ = "" # path to trace file
generation_ = 0 # generation to which this individual belonged
indiv_ = 0 # identify this individual by number
# constructor
def __init__(self, gen, indv):
# assign indices
self.generation_ = gen
self.indiv_ = indv
self.fitness_ = random.random()
# populate genome
for lp in cfg.params_:
g = Gene(lp[0], lp[1])
self.Genes_.append(g)
print len(self.Genes_)
> python ga.py
> 24
> 48
> 72
> 96
> 120
> 144
......
正如您所看到的,每个人应该有24个基因,但是这个群体爆发得非常快。 我创建了一个像这样的新个人的初始人口:
# create a randomized initial population
def createPopulation(self, gen):
loc_population = []
for i in range(0, cfg.population_size_):
indv = Individual(gen, i)
loc_population.append(indv)
return loc_population
以及后来我的主循环(为整个转储道歉,但觉得有必要 - 如果需要我的二次调用(突变/交叉)请告诉我))
for i in range(0, cfg.generations_):
# evaluate current population
self.evaluate(i)
# sort population on fitness
loc_pop = sorted(self.population_, key=operator.attrgetter('fitness_'), reverse=True)
# create next population & preserve elite individual
next_population = []
elitist = copy.deepcopy(loc_pop[0])
elitist.generation_ = i
next_population.append(elitist)
# perform selection
selection_pool = []
selection_pool = self.selection(elitist)
# perform crossover on selection
new_children = []
new_children = self.crossover(selection_pool, i)
# perform mutation on selection
muties = []
muties = self.mutation(selection_pool, i)
# add members to next population
next_population = next_population + new_children + muties
# fill out the rest with random
for j in xrange(len(next_population)-1, cfg.population_size_ - 1):
next_population.append(Individual(i, j))
# copy next population over old population
self.population_ = copy.deepcopy(next_population)
# clear old lists
selection_pool[:] = []
new_children[:] = []
muties[:] = []
next_population[:] = []
答案 0 :(得分:1)
我不是完全确定我理解你的问题,但我怀疑你的问题是你的Individual()类中的Genes_变量是在类名称空间中声明的。该命名空间可供该类的所有成员使用。换句话说,Individual()的每个实例将共享相同的变量Genes _。
考虑以下两个片段:
class Individual():
# genome definition
genes = []
def __init__(self):
for i in xrange(10):
self.genes.append(i)
ind_1 = Individual()
print ind_1.genes
ind_2 = Individual()
print ind_1.genes
print ind_2.genes
和
class Individual():
# genome definition
def __init__(self):
self.genes = []
for i in xrange(10):
self.genes.append(i)
ind_1 = Individual()
print ind_1.genes
ind_2 = Individual()
print ind_1.genes
print ind_2.genes
第一个片段输出
>>> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
而第二个片段输出
>>> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
在第一个场景中,当第二个Individual()被实例化时,基因列表变量已经存在,并且来自第二个体的基因被添加到现有列表中。
而不是像这样创建Individual()类,
# individual class
class Individual():
# genome definition
Genes_ = [] # genes list
# constructor
def __init__(self, gen, indv):
# assign indices
self.generation_ = gen
self.indiv_ = indv
self.fitness_ = random.random()
你应该考虑在 init 中声明Genes_变量,以便每个Individual()实例获得自己的基因集
# individual class
class Individual():
# constructor
def __init__(self, gen, indv):
# genome definition
self.Genes_ = [] # genes list
# assign indices
self.generation_ = gen
self.indiv_ = indv
self.fitness_ = random.random()
答案 1 :(得分:1)
当你创建一个类时,你实际上只创建了一个“类对象”。这些对象就像Python中的任何其他对象一样; Python中的所有东西都是一个对象,这些对象的作用是由它们的方法定义的,而不是它们的类!这就是鸭子打字的神奇之处。在Python中,您甚至可以动态地动态创建新类。
无论如何,您只将一个列表对象添加到一个且仅“Individuals”类对象的“Genes_”属性中。结果是“Individual”类对象的每个实例对象都访问相同的“Genes_”列表对象。
考虑一下
# In 2.2 <= Python < 3.0 you should ALWAYS inherit from 'object'.
class Foobar(object):
doodah = []
a = Foobar()
b = Foobar()
assert id(a.doodah) == id(b.doodah) # True
在这种情况下,正如你所看到的,“a.doodah”和“b.doodah”是同一个对象!
class Foobar(object):
def __init__(self):
self.doodah = []
a = Foobar()
b = Foobar()
assert id(a.doodah) != id(b.doodah) # True
在这种情况下,它们是不同的对象。
可以吃蛋糕也可以吃。考虑一下这个
class Foobar(object):
doodah = []
a = Foobar()
b = Foobar()
a.doodah = 'hlaghalgh'
assert id(a.doodah) != id(b.doodah) # True
在这种情况下,“doodah”属性被添加到“a”对象,该属性将覆盖类属性。
希望这有帮助!