使用 Python 的 AI – 遗传算法
本章详细讨论了 AI 的遗传算法。
什么是遗传算法?
遗传算法 (GA) 是基于自然选择和遗传学概念的搜索算法。GA 是计算的一个更大的分支,称为进化计算的一个子集。
GA 由密歇根大学的 John Holland 和他的学生和同事开发,其中最著名的是 David E. Goldberg。自那以后,它已在各种优化问题上进行了尝试,并取得了很高的成功率。
在 GA 中,我们有一个针对给定问题的可能解决方案池。然后,这些解决方案会进行重组和突变(就像在自然遗传学中一样),产生新的子代,并且该过程会在各个代中重复。每个个体(或候选解决方案)都被分配一个适应度值(基于其目标函数值),适应度更高的个体有更高的机会交配并产生适应度的个体。这符合达尔文的适者生存理论。
因此,它会在几代人中不断进化出更好的个体或解决方案,直到达到停止标准。
遗传算法本质上具有足够的随机性,但它们的性能比随机局部搜索(我们只是尝试随机解决方案,跟踪迄今为止最好的解决方案)好得多,因为它们也利用了历史信息。
如何使用 GA 解决优化问题?
优化是一种使设计、情况、资源和系统尽可能有效的行为。下面的框图显示了优化过程 −
GA 机制用于优化过程的阶段
以下是 GA 机制用于优化问题时的步骤顺序。
步骤 1 − 随机生成初始种群。
步骤 2 − 选择具有最佳适应度值的初始解决方案。
步骤 3 − 使用突变和交叉运算符重新组合选定的解决方案。
步骤 4 − 将后代插入种群。
步骤 5 − 现在,如果满足停止条件,则返回具有最佳适应度值的解决方案。否则转到步骤 2。
安装必要的软件包
为了使用 Python 中的遗传算法解决问题,我们将使用一个名为 DEAP 的强大 GA 软件包。它是一个新颖的进化计算框架库,用于快速原型设计和测试想法。我们可以在命令提示符下使用以下命令安装此包 −
pip install deap
如果您使用的是 anaconda 环境,则可以使用以下命令安装 deap −
conda install -c conda-forge deap
使用遗传算法实现解决方案
本节向您介绍如何使用遗传算法实现解决方案。
生成位模式
以下示例向您展示如何基于 One Max 问题生成包含 15 个 1 的位字符串。
按照所示导入必要的包 −
import random from deap import base, creator, tools
定义评估函数。这是创建遗传算法的第一步。
def eval_func(individual): target_sum = 15 return len(individual) - abs(sum(individual) - target_sum),
现在,使用正确的参数创建工具箱 −
def create_toolbox(num_bits):
creator.create("FitnessMax", base.Fitness, weights=(1.0,))
creator.create("Individual", list, fitness=creator.FitnessMax)
初始化工具箱
toolbox = base.Toolbox()
toolbox.register("attr_bool", random.randint, 0, 1)
toolbox.register("individual", tools.initRepeat, creator.Individual,
toolbox.attr_bool, num_bits)
toolbox.register("population", tools.initRepeat, list, toolbox.individual)
注册评估运算符 −
toolbox.register("evaluate", eval_func)
现在,注册交叉运算符 −
toolbox.register("mate", tools.cxTwoPoint)
注册突变运算符 −
toolbox.register("mutate", tools.mutFlipBit, indpb = 0.05)
定义育种运算符 −
toolbox.register("select", tools.selTournament, tournsize = 3)
return toolbox
if __name__ == "__main__":
num_bits = 45
toolbox = create_toolbox(num_bits)
random.seed(7)
population = toolbox.population(n = 500)
probab_crossing, probab_mutating = 0.5, 0.2
num_generations = 10
print('
Evolution process starts')
评估整个群体−
fitnesses = list(map(toolbox.evaluate, population))
for ind, fit in zip(population, fitnesses):
ind.fitness.values = fit
print('
Evaluated', len(population), 'individuals')
创建并迭代代数 −
for g in range(num_generations):
print("
- Generation", g)
选择下一代个体 −
offspring = toolbox.select(population, len(population))
现在,克隆选定的个体 −
offspring = list(map(toolbox.clone, offspring))
对后代应用交叉和变异 −
for child1, child2 in zip(offspring[::2], offspring[1::2]): if random.random() < probab_crossing: toolbox.mate(child1, child2)
删除 child 的适应度值
del child1.fitness.values del child2.fitness.values
现在,应用变异 −
for mutant in offspring: if random.random() < probab_mutating: toolbox.mutate(mutant) del mutant.fitness.values
评估适应度无效的个体−
invalid_ind = [ind for ind in offspring if not ind.fitness.valid]
fitnesses = map(toolbox.evaluate, invalid_ind)
for ind, fit in zip(invalid_ind, fitnesses):
ind.fitness.values = fit
print('Evaluated', len(invalid_ind), 'individuals')
现在,用下一代个体 − 替换人口
population[:] = offspring
打印当前代的统计数据 −
fits = [ind.fitness.values[0] for ind in population]
length = len(population)
mean = sum(fits) / length
sum2 = sum(x*x for x in fits)
std = abs(sum2 / length - mean**2)**0.5
print('Min =', min(fits), ', Max =', max(fits))
print('Average =', round(mean, 2), ', Standard deviation =',
round(std, 2))
print("
- Evolution ends")
打印最终输出 −
best_ind = tools.selBest(population, 1)[0]
print('
Best individual:
', best_ind)
print('
Number of ones:', sum(best_ind))
Following would be the output:
Evolution process starts
Evaluated 500 individuals
- Generation 0
Evaluated 295 individuals
Min = 32.0 , Max = 45.0
Average = 40.29 , Standard deviation = 2.61
- Generation 1
Evaluated 292 individuals
Min = 34.0 , Max = 45.0
Average = 42.35 , Standard deviation = 1.91
- Generation 2
Evaluated 277 individuals
Min = 37.0 , Max = 45.0
Average = 43.39 , Standard deviation = 1.46
… … … …
- Generation 9
Evaluated 299 individuals
Min = 40.0 , Max = 45.0
Average = 44.12 , Standard deviation = 1.11
- Evolution ends
Best individual:
[0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1,
1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0,
1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1]
Number of ones: 15
符号回归问题
这是遗传编程中最著名的问题之一。所有符号回归问题都使用任意数据分布,并尝试使用符号公式拟合最准确的数据。通常,使用 RMSE(均方根误差)等度量来衡量个体的适应度。这是一个经典的回归问题,这里我们使用方程式 5x3-6x2+8x=1。我们需要遵循上述示例中的所有步骤,但主要部分是创建原始集,因为它们是个体的构建块,因此可以开始评估。这里我们将使用经典的原始集。
以下 Python 代码详细解释了这一点 −
import operator
import math
import random
import numpy as np
from deap import algorithms, base, creator, tools, gp
def division_operator(numerator, denominator):
if denominator == 0:
return 1
return numerator / denominator
def eval_func(individual, points):
func = toolbox.compile(expr=individual)
return math.fsum(mse) / len(points),
def create_toolbox():
pset = gp.PrimitiveSet("MAIN", 1)
pset.addPrimitive(operator.add, 2)
pset.addPrimitive(operator.sub, 2)
pset.addPrimitive(operator.mul, 2)
pset.addPrimitive(division_operator, 2)
pset.addPrimitive(operator.neg, 1)
pset.addPrimitive(math.cos, 1)
pset.addPrimitive(math.sin, 1)
pset.addEphemeralConstant("rand101", lambda: random.randint(-1,1))
pset.renameArguments(ARG0 = 'x')
creator.create("FitnessMin", base.Fitness, weights = (-1.0,))
creator.create("Individual",gp.PrimitiveTree,fitness=creator.FitnessMin)
toolbox = base.Toolbox()
toolbox.register("expr", gp.genHalfAndHalf, pset=pset, min_=1, max_=2)
toolbox.expr)
toolbox.register("population",tools.initRepeat,list, toolbox.individual)
toolbox.register("compile", gp.compile, pset = pset)
toolbox.register("evaluate", eval_func, points = [x/10. for x in range(-10,10)])
toolbox.register("select", tools.selTournament, tournsize = 3)
toolbox.register("mate", gp.cxOnePoint)
toolbox.register("expr_mut", gp.genFull, min_=0, max_=2)
toolbox.register("mutate", gp.mutUniform, expr = toolbox.expr_mut, pset = pset)
toolbox.decorate("mate", gp.staticLimit(key = operator.attrgetter("height"), max_value = 17))
toolbox.decorate("mutate", gp.staticLimit(key = operator.attrgetter("height"), max_value = 17))
return toolbox
if __name__ == "__main__":
random.seed(7)
toolbox = create_toolbox()
population = toolbox.population(n = 450)
hall_of_fame = tools.HallOfFame(1)
stats_fit = tools.Statistics(lambda x: x.fitness.values)
stats_size = tools.Statistics(len)
mstats = tools.MultiStatistics(fitness=stats_fit, size = stats_size)
mstats.register("avg", np.mean)
mstats.register("std", np.std)
mstats.register("min", np.min)
mstats.register("max", np.max)
probab_crossover = 0.4
probab_mutate = 0.2
number_gen = 10
population, log = algorithms.eaSimple(population, toolbox,
probab_crossover, probab_mutate, number_gen,
stats = mstats, halloffame = hall_of_fame, verbose = True)
请注意,所有基本步骤与生成位模式时使用的步骤相同。经过 10 次生成后,此程序将输出 min、max、std(标准差)。

