基本思路
02代码实现
1)主函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 def main (): print ('y = 10 * sin(5 * x) + 7 * cos(4 * x)' ) plot_obj_func() size = 500 start = 0 end = 10 bit = 2 iter = 500 pc = 0.6 pm = 0.01 mini = 0 results = [] best_x = [] best_y = [] x = create_num(start,end,bit,size) for i in range (iter ): y = fitness(x) fit_value = calc_fit_value(y,mini) now_best_x,now_best_y = find_best(x,fit_value) best_x.append(now_best_x) best_y.append(now_best_y) selection(x,fit_value) gene = code(x,end,bit,size) crossover(gene, pc) mutation(gene,pm) x = decode(gene,bit) plot_currnt_individual(x,fitness(x)) plot_iter_curve(iter ,best_y) print (max (best_y))
主函数展示了算法的整体思路,即
①确定各参数(种群数量、函数自变量范围、自变量精确度、演化代数、杂交及变异概率)
②产生个体,对个体进行评价
③更新个体,将不适应的个体清除
④重新生成新的种群(通过重新选择、交叉、变异产生)
重复③④直到满足设定的迭代次数
得到迭代过程中的最优解
2)个体生成函数
1 2 3 4 5 6 7 def create_num (start,end,bit,size ): listx = [] for i in range (size): listx.append(round (random.uniform(start,end),bit)) return listx
random.uniform()
生成随机浮点数,round()设置小数点后位数,获得初代个体,保存至列表
3)计算适应度
1 2 3 4 def fitness (x ): Y = [10 * math.sin(5 * i) + 7 * math.cos(4 * i) for i in x] return Y
适应度即随机生成的x值对应的函数值
4)淘汰个体
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 def calc_fit_value (value_y,mini ): fit_value = [] c_min = mini for value in value_y: if value > c_min: temp = value else : temp = 0. fit_value.append(temp) return fit_value
通过适应度,将淘汰个体适应度(函数值)变为0,保证在后续个体选择时不会选中它
5)选出当代最优个体
1 2 3 4 5 def find_best (x,y ): value_y = max (y) value_x = x[y.index(value_y)] return value_x,value_y
找出当前代最优个体,进行记录,供最后查看代际迭代情况
6)轮盘赌选择个体
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 def selection (now_x,now_value ): value_rate = [] total_fit = sum (now_value) for i in range (len (now_value)): value_rate.append(now_value[i] / total_fit) value_rate = np.cumsum(value_rate) x_len = len (now_x) ms = sorted ([random.random() for i in range (x_len)]) fitin = 0 newin = 0 new_gen = now_x while newin < x_len: if (ms[newin] < value_rate[fitin]): new_gen[newin] = now_x[fitin] newin = newin + 1 else : fitin = fitin + 1 x = new_gen
轮盘赌基本思想:每个个体的适应度/总适应度 就是改个体被选中的概率,然后将其累加,得到0-1的圆盘,通过随机数进行选择。是印度越大,在轮盘上所占据空间越大,被选中的概率也越大。
本算法轮盘赌选择的个体有重复选择的情况出现
7)编码
1 2 3 4 5 6 7 8 9 10 def code (listx,end,bit,size ): len_gen = len (bin (end*10 **bit))-2 gene = [round (100 *x) for x in listx] for i in range (size): gene[i] = bin (gene[i])[2 :].rjust(len_gen,'0' ) return gene
将所选中的x变为相应的二进制编码,以进行交叉变异。
编码思路为:
因随机生成x存在小数,首先将小数放大10的n次方,变为整数,之后对该整数进行编码
编码过程中出现取值范围的最小值与最大值转化出的二进制表达,其长度不相同(eg.10→1010,1000→1111101000),因此把最大取值的二进制长度作为染色体长度,不足的在前面补0。
将所有x转化为相应的二进制形式放入列表[gene]进行存储
8)交叉
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 def crossover (pop, pc ): pop_len = len (pop) i = 0 while i < pop_len : if (random.random() < pc): rand1 = random.randint(0 , len (pop)-1 ) rand2 = random.randint(0 , len (pop)-1 ) cpoint = random.randint(1 , len (pop[0 ])-1 ) out1 = pop[rand1][0 :cpoint] out2 = pop[rand1][cpoint:] out3 = pop[rand2][0 :cpoint] out4 = pop[rand2][cpoint:] pop[i] = out1 + out4 pop[i+1 ] = out2 + out3 i+=2
交叉变异为算法核心之一,此处交叉选择的是又放回的从种群中随机抽取两个个体进行染色体交叉,生成两个新的个体。
如果达到杂交概率,则子代两个个体由父代杂交生成,否则直接继承父代染色体。
每次杂交生成两个个体,直到新生成的子代个体数达到设定的种群数量。
个体选择及染色体交叉点通过random.randint()函数生成
新染色体通过字符串切片,将两条染色体分为4份,进行重新拼接
9)变异
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 def mutation (pop,pm ): px = len (pop) py = len (pop[0 ]) for i in range (px): if (random.random() < pm): mpoint = random.randint(0 , py - 1 ) if (pop[i][mpoint] == 1 ): pop[i] = pop[i][:mpoint] + '0' + pop[i][mpoint+1 :] else : pop[i] = pop[i][:mpoint] + '1' + pop[i][mpoint+1 :]
杂交产生的子代染色体存在一定概率突变,因此设定突变概率,对每个子代染色体:
生成随机数判断是否突变,
若没有,则染色体不变,确定为子代染色体
若发生突变,则随机选取染色体某一位置的数字进行取反(0变1,1变0),完成突变,成为子代染色体
!至此,子代已经确定,可以进行下一轮的自然选择
10)解码
1 2 3 4 5 6 7 8 9 def decode (ones,bit ): tens = [] for i in range (len (ones)): ten = int (ones[i],2 ) tens.append(ten) for i in range (len (ones)): tens[i] = tens[i]/10 **bit return tens
通过交叉变异得到的子代是染色体形式,在进行自然选择的时候根据其实际数值进行,因此需要进行解码。
解码过程为:
首先将十位染色体编码,通过int()变为十进制整数,
之后除以10的n次方,变为定义域范围内的自变量函数值
11)结果展示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 def plot_obj_func (): """y = 10 * math.sin(5 * x) + 7 * math.cos(4 * x)""" X1 = [i / float (10 ) for i in range (0 , 100 , 1 )] Y1 = [10 * math.sin(5 * x) + 7 * math.cos(4 * x) for x in X1] plt.plot(X1, Y1) plt.show() def plot_currnt_individual (current_x, current_y ): X1 = [i / float (10 ) for i in range (0 , 100 , 1 )] Y1 = [10 * math.sin(5 * x) + 7 * math.cos(4 * x) for x in X1] plt.plot(X1, Y1) plt.scatter(current_x,current_y, c='r' , s=5 ) plt.show() def plot_iter_curve (iter , results ): X = [i for i in range (iter )] Y = [results[i] for i in range (iter )] plt.plot(X, Y) plt.show()
#查看要处理函数:对所求问题代表的函数进行画图,直观展示
#查看当前种群落点情况:将当前种群的个体情况(x和y值)以点的形式展现出来
#查看迭代过程中结果变化:因记录了每一代的最优个体,因此可以查看迭代过程中,每一代最优解的变化情况
12)运行程序
1 2 3 4 start_time = time.time() main() end_time = time.time() print ('Took %f second' % (end_time - start_time))
设置了时间统计,记录算法运行花费时间
13)用到的库
1 2 3 4 5 import matplotlib.pyplot as pltimport mathimport randomimport numpy as npimport time
运行结果
最终运行结果:
输出所求函数表达式、函数图形、最后一代种群分布、迭代过程中的最优解变化情况
参考资料
遗传算法(GA)的新手入门必备,python3案例_hiudawn-CSDN博客_遗传算法python实例