文献题名:
遗传算法(Genetic Algorithm, GA) :在求解的过程中,进化算法首先随机生成一个种群,并对种群中的个体进行适应度计算,之后通过选择操作选择出适应度高的个体作为父代个体,然后对其进行交叉和变异等操作并生成一个新的种群(即一组新的近似解),最后通过循环上述过程,不断逼近问题近似最优解。
(以TSP问题为例,计算适应度就是计算路线长度)
遗传算法对应概念
遗传算法试图找到给定问题的最佳解。达尔文进化论保留了种群的个体性状,而遗传算法则保留了针对给定问题的候选解集合(也称为individuals)。这些候选解经过迭代评估(evaluate),用于创建下一代解。更优的解有更大的机会被选择,并将其特征传递给下一代候选解集合。这样,随着代际更新,候选解集合可以更好地解决当前的问题。
基因型(Genotype)
在自然界中,通过基因型表征繁殖,繁殖和突变,基因型是组成染色体的一组基因的集合。
在遗传算法中,每个个体都由代表基因集合的染色体构成。例如,一条染色体可以表示为二进制串,其中每个位代表一个基因:
种群(Population)
遗传算法保持大量的个体(individuals)——针对当前问题的候选解集合。由于每个个体都由染色体表示,因此这些种族的个体(individuals)可以看作是染色体集合:
适应度函数(Fitness function)
在算法的每次迭代中,使用适应度函数(也称为目标函数)对个体进行评估。目标函数是用于优化的函数或试图解决的问题。
适应度得分更高的个体代表了更好的解,其更有可能被选择繁殖并且其性状会在下一代中得到表现。随着遗传算法的进行,解的质量会提高,适应度会增加,一旦找到具有令人满意的适应度值的解,终止遗传算法。
选择(Selection)
在计算出种群中每个个体的适应度后,使用选择过程来确定种群中的哪个个体将用于繁殖并产生下一代,具有较高值的个体更有可能被选中,并将其遗传物质传递给下一代。
仍然有机会选择低适应度值的个体,但概率较低。这样,就不会完全摒弃其遗传物质。
交叉(Crossover)
为了创建一对新个体,通常将从当前代中选择的双亲样本的部分染色体互换(交叉),以创建代表后代的两个新染色体。此操作称为交叉或重组:
突变(Mutation)
突变操作的目的是定期随机更新种群,将新模式引入染色体,并鼓励在解空间的未知区域中进行搜索。
突变可能表现为基因的随机变化。变异是通过随机改变一个或多个染色体值来实现的。例如,翻转二进制串中的一位:
遗传算法(Genetic Algorithm)详解与实现_盼小辉丶的博客-CSDN博客
【建模算法】基于遗传算法求解TSP问题(Python实现)_遗传算法python tsp_果州做题家的博客-CSDN博客
遗传算法代码:
# This is a sample Python script.
# Press Shift+F10 to execute it or replace it with your code.
# Press Double Shift to search everywhere for classes, files, tool windows, actions, and settings.
import math
import random
import operator
class GA():
def __init__(self, length, count):
self.length = length #染色体长度
self.count = count #种群中染色体数量
self.population = self.gen_population(length, count) #随机生成初始种群
def evolve(self,retain_rate = 0.2, random_select_rate = 0.5, mutation_rate = 0.01):
"""
进化,对当前一代种群一次进行选择,交叉并产生新一代种群,然后对新一代种群进行变异
"""
parents = self.selection(retain_rate, random_select_rate)
self.crossover(parents)
self.mutation(mutation_rate)
def gen_chromosome(self, length):
"""
随机生成长度为length的染色体,每个基因的取值是0或1
用一个bit表示一个基因
"""
chromosome = 0
for i in range(length):
chromosome |= (1 << i) * random.randint(0,1)
return chromosome
def gen_population(self,length,count):
"""
获取初始种群(一个含有count个长度为length的染色体列表)
"""
return [self.gen_chromosome(length) for i in range(count)]
def fitness(self, chromosome):
"""
计算适应度,将染色体解码在0-9之间的数字,带入函数计算
因为是求最大值,所以数值越大,适应度越高
"""
x = self.decode(chromosome)
return x + 10*math.sin(5*x) + 7*math.cos(4*x)
def selection(self, retain_rate, random_select_rate):
"""
选择
先对适应度从大到小排序,选出存活的染色体
在进行随机选择,选出适应度虽然小,但是幸存下来的个体
"""
#对适应度从大到小排序
graded = [(self.fitness(chromosome), chromosome) for chromosome in self.population]
graded = [x[1] for x in sorted(graded, reverse = True)]
#选出适应性强的染色体
retain_length = int(len(graded) * retain_rate)
parents = graded[:retain_length]
#选出是是影响不强,但是幸存的染色体
for chromosome in graded[retain_length:]:
if random.random() < random_select_rate:
parents.append(chromosome)
return parents
def crossover(self,parents):
"""
染色体的交叉,反之,生成新一代的种群
"""
#新出生的孩子,最终会被加入存活下来的父母之中,形成新一代的种群
children = []
#需要繁殖的孩子的量
target_count = len(self.population) - len(parents)
#开始根据需要的量进行繁殖
while len(children) < target_count:
male = random.randint(0, len(parents)-1)
female = random.randint(0, len(parents)-1)
if male != female:
#随机选取交叉点
cross_pos = random.randint(0, self.length)
#生成掩码,方便位操作
mask = 0
for i in range(cross_pos):
mask |= (1 << i)
male = parents[male]
female = parents[female]
#孩子将获得父亲在交叉点前的基因和母亲在交叉点后(包括交差点)的基因
child = ((male & mask) | (female & ~mask)) & ((1<<self.length) - 1)
children.append(child)
#经过繁殖后,孩子和父母的数量与原始种群数量相等,可以更新种群
self.population = parents + children
def mutation(self, rate):
"""
变异,对种群的所有个体,随机改变某个个体中的某个基因
"""
for i in range(len(self.population)):
if random.random() < rate:
j = random.randint(0, self.length-1)
self.population[i] ^= 1 << j
def decode(self,chromosome):
"""
解码染色体,将二进制转或成属于【0,9】的实数
"""
return chromosome * 9.0 / (2**self.length-1)
def result(self):
"""
获得当前代的最优值,这里取的是函数取最大值时候的x的值
"""
graded = [(self.fitness(chromosome), chromosome) for chromosome in self.population]
graded = [x[1] for x in sorted(graded, reverse = True)]
return ga.decode(graded[0])
if __name__ == '__main__':
#染色体长度为17,种群数量为300
ga = GA(10,30)
#200次迭代
for x in range(90):
ga.evolve()
print (ga.result())
1.选择的作用:优胜劣汰,适者生存;
2 交叉的作用:保证种群的稳定性,朝着最优解的方向进化;
3变异的作用:保证种群的多样性,避免交叉可能产生的局部收敛。
进化策略(Evolution Strategy):
(杀死不乖的宝宝,让乖宝宝继续生乖宝宝)
(1+1)-ES
import numpy as np
import matplotlib.pyplot as plt
DNA_SIZE = 1 # DNA (real number)
DNA_BOUND = [0, 5] # solution upper and lower bounds
N_GENERATIONS = 200
MUT_STRENGTH = 5. # initial step size (dynamic mutation strength)
def F(x): return np.sin(10*x)*x + np.cos(2*x)*x # to find the maximum of this function
# find non-zero fitness for selection
def get_fitness(pred): return pred.flatten()
def make_kid(parent):
# no crossover, only mutation
k = parent + MUT_STRENGTH * np.random.randn(DNA_SIZE)
k = np.clip(k, *DNA_BOUND)
return k
def kill_bad(parent, kid):
global MUT_STRENGTH
fp = get_fitness(F(parent))[0]
fk = get_fitness(F(kid))[0]
p_target = 1/5
if fp < fk: # kid better than parent
parent = kid
ps = 1. # kid win -> ps = 1 (successful offspring)
else:
ps = 0.
# adjust global mutation strength
MUT_STRENGTH *= np.exp(1/np.sqrt(DNA_SIZE+1) * (ps - p_target)/(1 - p_target))
return parent
parent = 5 * np.random.rand(DNA_SIZE) # parent DNA
plt.ion() # something about plotting
x = np.linspace(*DNA_BOUND, 200)
for _ in range(N_GENERATIONS):
# ES part
kid = make_kid(parent)
py, ky = F(parent), F(kid) # for later plot
parent = kill_bad(parent, kid)
# something about plotting
plt.cla()
plt.scatter(parent, py, s=200, lw=0, c='red', alpha=0.5,)
plt.scatter(kid, ky, s=200, lw=0, c='blue', alpha=0.5)
plt.text(0, -7, 'Mutation strength=%.2f' % MUT_STRENGTH)
plt.plot(x, F(x)); plt.pause(0.05)
plt.ioff(); plt.show()