我试图了解如何实现遗传算法并编写一个简单的字符串猜测。我无法理解为什么这个解决方案不起作用。
我相信我的问题在于我的新一代?最新一代似乎没有改善健身价值。我也不确定我是否正确地进行交叉和突变率。任何帮助都会非常感激!
POP_SIZE = 300;
CROSSOVER_RATE = 0.7;
MUTATION_RATE = 0.01
GENESET = " abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"
target = "Hello World"
RAND_NUM = random.random()
def generateBasePopulation(population_size):
population = dict()
for _ in range(POP_SIZE):
gene = generateParent(len(target))
population[gene] = 0
return population
def generateNewPopulation(population, population_size):
newPopulation = dict()
while(len(newPopulation) <= POP_SIZE):
child_one, child_two = crossover(child_one, child_two)
child_one = mutate(child_one)
child_two = mutate(child_two)
newPopulation[child] = 0
newPopulation[child_two] = 0
return newPopulation
def assignFitness(population):
for x in population:
population[x] = getFitness(x)
def generateParent(length):
genes = list("")
for i in range(0,length):
random_gene = random.choice(GENESET)
genes.append(random_gene)
return(''.join(genes))
def getFitness(candidate):
fitness = 0
for i in range(0, len(candidate) - 1):
if target[i] == candidate[i]:
fitness += 1
return(fitness)
def mutate(parent):
gene_index_to_mutate = random.randint(0, len(parent) - 1)
mutation_value = random.choice(GENESET)
genes = list(parent)
genes[gene_index_to_mutate] = mutation_value
return(''.join(genes))
def crossover(parentA, parentB):
if(RAND_NUM < CROSSOVER_RATE):
random_index = random.randint(0, len(target))
parentASlice = parentA[:random_index]
parentBSlice = parentB[random_index:]
return (parentASlice + parentBSlice), (parentBSlice + parentASlice)
return parentA, parentB
def chooseChild(population):
fitnessSum = sum(population.values())
pick = random.uniform(0, fitnessSum)
current = 0
for pop in population:
current += population[pop]
if current >= pick:
return pop
def main():
population = generateBasePopulation(POP_SIZE)
targetNotFound = True
while(targetNotFound):
assignFitness(population)
if target in population:
print("target found!")
targetNotFound = False
if(targetNotFound):
tempPopulation = generateNewPopulation(population, POP_SIZE)
population.clear()
population = tempPopulation
答案 0 :(得分:1)
generateNewPopulation
功能存在一些问题。
child_one
和child_two
您需要来自人口的两个人来执行交叉。有几种选择算法,但只是为了给出一个想法,你可以从tournament selection:
的形式开始def extractFromPopulation(population):
best = random.choice(list(population.keys()))
for _ in range(4):
gene = random.choice(list(population.keys()))
if population[gene] > population[best]:
best = gene
return best
此处选择压力(range(4)
)是固定的。这是你在一个真实案例中要调整的参数之一。
现在我们有:
def generateNewPopulation(population, population_size):
newPopulation = dict()
while len(newPopulation) <= POP_SIZE:
child_one = extractFromPopulation(population)
child_two = extractFromPopulation(population)
# ...
代码仍无效,因为
newPopulation
只需缩进两行:
newPopulation[child] = 0
newPopulation[child_two] = 0
(它们必须是while
循环的一部分)
修订后的generateNewPopulation
函数如下:
def generateNewPopulation(population, population_size):
newPopulation = dict()
while len(newPopulation) <= POP_SIZE:
child_one = extractFromPopulation(population)
child_two = extractFromPopulation(population)
child_one, child_two = crossover(child_one, child_two)
child_one = mutate(child_one)
child_two = mutate(child_two)
newPopulation[child_one] = 0
newPopulation[child_two] = 0
return newPopulation
crossover
函数不能基于固定的RAND_NUM
值删除RAND_NUM = random.random()
分配并更改crossover
功能,以便在每次通话时使用新的随机值:
def crossover(parentA, parentB):
if random.random() < CROSSOVER_RATE:
random_index = random.randint(0, len(target))
parentASlice = parentA[:random_index]
parentBSlice = parentB[random_index:]
return (parentASlice + parentBSlice), (parentBSlice + parentASlice)
return parentA, parentB
此外,代码无法正确执行单点交叉,因为未保留第二个父级的模式。
您可以更改许多细节以提高性能,但是,作为一个开始示例,它可能已经足够(......它可以工作)。
查找解决方案的平均代数约为158
(200
次运行的平均值)。
编辑(感谢 alexis 代表comment)
MUTATION_RATE
未使用,并且始终发生突变。 mutate
函数应该是这样的:
def mutate(parent):
if random.random() < MUTATION_RATE:
gene_index_to_mutate = random.randint(0, len(parent) - 1)
mutation_value = random.choice(GENESET)
genes = list(parent)
genes[gene_index_to_mutate] = mutation_value
return ''.join(genes)
return parent
如果您保留轮盘赌选择算法(chooseChild
通常在没有修复的情况下不会收敛),此修复尤其重要。