遗传算法(Genetic Algorithm, GA)
顾名思义是模仿生物的遗传学机理进行计算模拟最优解的过程。
将生物种群特征与问题进行对应
一个染色体代表问题的一个解(一个染色体含有多个基因)
一个基因代表问题的一个决策变量
多个个体构成一个种群,多组解构成解的种群。
我们使问题解的种群不断的优胜劣汰,像自然界的自然选择一般,直到最后剩下一个获胜的最优解,便结束了问题的求解。
随机生成一个种群。其中基因需要编码。
常用的编码方式有二进制编码法,浮点编码法,符号编码法。
今天先来做个二进制编码法,其解码、编码、交叉、变异等操作简单易行,但是由于随机性,局部搜索能力较差。
“与人类的染色体不同,我们假设只有“0”和“1”两种碱基,因此只需要将我们的决策变量进行二进制编码即可获得基因序列。”
可以直接用函数值作为适应度,我们要找最小值嘛。
选定一个交配概率pc
可以设置若干迭代次数作为终止条件。
emmm,是在csdn的必问上看到一个问题,要求寻找目标函数的全局最小值
就打算拿这个试一下
首先初始化种群,如果是n维输入的话,每个染色体上都应该有n个基因,分别代表 x 1 . . . . . x n x_1.....x_n x1.....xn
这个时候需要先考虑一些如何进行二进制编码。
x的范围是-32.77到32.77,我选用13位二进制数来编码。
将一个二进制串代表的二进制数转化为十进制数:
( b 0 . . . . . . b n ) = ( Σ i = 0 n b i 2 i ) = x ′ (b_0......b_n)=(\Sigma^n_{i=0}b_i2^i)=x' (b0......bn)=(Σi=0nbi2i)=x′
对应区间内的实数:
x = − 32.77 + x ′ 65.54 2 13 − 1 x = - 32.77 + x'\frac{65.54}{2^{13}-1} x=−32.77+x′213−165.54
那么有还原的函数
def translation(L):#将二进制编码还原为变量
n = 0
for i in range(13):
n += L[i]*pow(2,i)
return -32.77 + n * (65.54/k)
这里用比较简单的选择方法,每个个体被选中的概率都是自身的适应度除以总适应度的和。
α i = F i Σ F \alpha_i = \frac{F_i}{\Sigma F} αi=ΣFFi
直接使用我们的目标函数,emmm好像不太成,这样的话越小的值适应度越小了,理论上应该是适应度越大才对。
def f(x):#目标函数
n = len(x)
return -20*np.exp(-0.2*np.sqrt(1/n*sum(np.power(x,2))))\
-np.exp(1/n*sum(np.cos(2*pi*x))) + 20
不过那也好说,我们可以找出来所有个体的最大值,然后用这个值减去各个个体的函数值作为其适应度,这样最大的一个的适应度就是0,自然死亡。
def fitness(popular):
fit = [0] * len(popular)
n = len(popular[0])//13 #数据维度
maxfit = -1e5
for i in range(popular):
x = []
for j in range(n):
x.append(translation(i[j:j+13]))
fit[i] = f(np.array(x))
if fit[i] > maxfit:
maxfit = fit[i]
for i in range(len(fit)):
fit[i] = maxfit - fit[i]
return fit
接下来就是轮盘赌了,计算出所有的适应度然后根据概率判断新的种群中的个体
def choose(popular):#进行自然选择
popular_len = len(popular)#个体个数
survival_rate = []
for i in range(popular_len):
survival_rate.append(random.random())
fit = fitness(popular)#每个个体的存活率
best_individual = popular[fit.index(max(fit))]#保存下当前种群最优个体(其实写这里不太会)
survival_rate.sort()
fitin = 0
newin = 0
newpopular = popular
# 开始轮盘赌
# 结束之后,适应度更高的个体在新种群中应该更多
while newin < popular_len:
if survival_rate[newin] < fit[fitin]:
newpopular[newin] = popular[fitin]
newin += 1#旋转轮盘
else:
fitin += 1#旋转轮盘
popular = newpopular
return best_individual
取交叉率pc=0.5
def crossover(popular,pc):#pc为交叉率
popular_len=len(popular)
for i in range(popular_len-1):
crosspoint = random.randint(0,len(popular[0]))#随机生成交叉点
# 一个个体染色体长度为len(popular[0]),crosspoint为交换位置
#接下来我们让第i个个体和第i+1个个体发生交叉
t1 =[]
t2= []
t1.extend(popular[i][0:crosspoint])#i的前半段
t1.extend(popular[i+1][crosspoint:-1])#i+1的后半段
t2.extend(popular[i+1][0:crosspoint])#i+1的前半段
t2.extend(popular[i][crosspoint:-1])#i的后半段
# 放回种群
popular[i] = t1
popular[i+1] = t2
取变异率0.01吧
def mutation(popular,pm):#pm为变异率
popular_len=len(popular)
chromosome_len = len(popular[0])
for i in range(popular_len):
if random.random()>pm:#大于阈值则发生变异
mutation_point = random.randint(0,chromosome_len-1)
#发生变异
if popular[i][mutation_point] == 1:
popular[i][mutation_point] = 0
else:
popular[i][mutation_point] = 1
、
def GA(n):
## 初始化种群
popular_size = 100#种群大小
chromosome_length = n*13#染色体大小
popular = []
for i in range(popular_size):
individual = []
for j in range(chromosome_length):#生成随机基因
individual.append(random.randint(0,1))
popular.append(individual)#向种群添加一个个体
# 种群初始化完成
best_individual = []
for i in range(200):#迭代200次
best_individual.append( choose(popular) ) #保存下最优个体
crossover(popular,0.5)
mutation(popular,0.01)
solutions = []#解的迭代过程
for i in best_individual:
s = []
for j in range(n):
s.append(translation( i[13*j:13*j+13] ))
#还原为了十进制数
solutions.append(s)
return solutions#保存的是各次迭代发现的最优解,最后一个是结果
python代码