【发布时间】:2020-07-12 04:09:48
【问题描述】:
我正在学习遗传算法,为了更好地理解概念,我尝试使用 python 从头构建遗传算法,而不使用任何外部模块(只是标准库和一点点 numpy)
目标是找到一个目标字符串,所以如果我给它字符串 hello 并定义 26 个字符 + 一个空格,则有 26^5 种可能性,这是巨大的。因此需要使用遗传算法来解决这个问题。
我定义了以下函数:
生成总体:我们生成给定大小 n 的总体,我们生成具有随机字符 len(target) 的 n 个字符串的目标,我们将总体作为 str 列表返回
计算适应度分数:如果位置 i 处的字符等于目标位置 i 处的字符,我们会增加分数,代码如下:
def fitness(indiv,target):
score = 0
#print(indiv," vs ",target)
for idx,char in enumerate(list(target)):
if char == indiv[idx]:
score += 1
else:
score = 0
return score
选择父母,在父母之间交叉并产生新的孩子群体
以下是负责该功能的功能:
from numpy.random import choice
def crossover(p1,p2):
# we define a crossover between p1 and p2 (single point cross over)
point = random.choice([i for i in range (len(target))])
#print("Parents:",p1,p2)
# C1 and C2 are the new children, before the cross over point they are equalt to their prantes, after that we swap
c = [p1[i] for i in range(point)]
#print("Crossover point: ",point)
for i in range(point,len(p1)):
c.append(p2[i])
#print("Offsprings:", c1," and ", c2)
c = "".join(c)
# we mutate c too
c = mutate(c)
return c
def mutate(ind):
point = random.choice([i for i in range (len(target))])
new_ind = list(ind)
new_ind[point] = random.choice(letters)
return "".join(new_ind)
def select_parent(new_pop,fit_scores):
totale = sum(fit_scores)
probs = [score/totale for score in fit_scores]
parent = choice(new_pop,1,p=probs)[0]
return parent
我通过计算每个人的概率(个人得分/总体得分)来选择父母,然后使用 加权随机选择 函数来选择父母(这是一个 numpy 函数) .
对于交叉,我正在生成一个子c 和一个随机分裂点,这个随机点之前的所有字符都是第一个父字符,分裂点之后的所有字符都是来自父字符的字符。
此外,我定义了一个名为 should_stop 的函数来检查我们是否找到了目标,并定义了 print_best 来从群体中选出最好的个体(最高适应度得分)。
然后我创建了一个使用上面定义的所有函数的查找函数:
def find(size,target,pop):
scores = [fitness(ind,target) for ind in pop]
#print("len of scores is ", len(scores))
#good_indiv = select_individuals(pop,scores)
#print("Length of good indivs is", len(good_indiv))
new_pop = []
# corssover good individuals
for ind in pop:
pa = select_parent(pop,scores)
pb = select_parent(pop,scores)
#print(pa,pb)
child = crossover(pa,pb)
#print(type(child))
new_pop.append(child)
best = print_best(new_pop,scores)
print("********** The best individual is: ", best, " ********")
return (new_pop,best)
n = 200
target = "hello"
popu = generate_pop(n,target)
#find(n,target,popu)
for i in range(1000):
print(len(popu))
data = find(n,target,popu)
popu = data[0]
print("iteration number is ", i)
if data[1] == target:
break
问题 问题在于生成 hello 需要的迭代次数过多(大多数时候迭代次数超过 200 次),而在本例中,它只需要很少的迭代次数: https://jbezerra.github.io/The-Shakespeare-and-Monkey-Problem/index.html
当然问题不是以相同的方式编码的,我使用 python 和一种程序方式来编码,但逻辑是相同的。那么我做错了什么?
【问题讨论】:
标签: python optimization genetic-algorithm heuristics