最近接触遗传算法,参考了众多例子,有些又不尽然对,所以自己边理解边修改,然后写出了下面这堆传说中的屎山。。。
PS1:遗传算法原理啥的太多了,就不赘述了,CSDN里面很多帖子都讲得很透彻了;
PS2:要看简洁的,直接油管搜遗传算法,看莫烦的视频。
不废话了,赶紧上车,啊不,上代码。
import math
import numpy as np
import matplotlib.pyplot as plt
import random
class GA(object):
# 目标求解2*sin(x)+cos(x)最大值
def __init__(self, population_size, chromosome_length, pm):
self.population_size = population_size
self.chromosome_length = chromosome_length
self.pm = pm
# 初始化种群
def species_origin(self): # 生成染色体和基因
population = [[]] # 二维列表,包含染色体和基因
for i in range(self.population_size):
temporary = [] # 染色体寄存器
for j in range(self.chromosome_length):
temporary.append(random.randint(0, 1)) # 生成基因,二进制
population.append(temporary) # 将基因添加到染色体中
return population[1:] # 返回种群,包含染色体和基因
# 种群解码,用于适应度判断
def translation(self, population): # 二进制转十进制
chromosome_d_list = [] # 创建染色体十进制列表
for i in range(len(population)):
chromosome_value_d = 0
for j in range(len(population[0])):
chromosome_value_d += population[i][j] * (math.pow(2, len(population[0])-j-1))
chromosome_d_list.append(chromosome_value_d)
return chromosome_d_list
# 适应度计算
def function(self, population, lower_bound, upper_bound):
all_fitness_list = [] # 创建所有染色体适应度列表
fv_list = self.translation(population)
for i in range(len(fv_list)):
x = lower_bound + fv_list[i] * (upper_bound - lower_bound)/(math.pow(2, self.chromosome_length) - 1)
y = 2 * math.sin(x) + math.cos(x) # 目标函数
all_fitness_list.append(y)
return all_fitness_list
# 剔除适应度负值
def positive_fitness(self, all_fitness_list):
pf = []
for i in range(len(all_fitness_list)):
if all_fitness_list[i] > 0:
pf.append(all_fitness_list[i])
return pf
# 正适应度染色体列表
def positive_chromosome(self, all_fitness_list, population):
positive_chromosome_list = []
for i in range(len(all_fitness_list)):
if all_fitness_list[i] > 0:
positive_chromosome_list.append(population[i])
return positive_chromosome_list
# 计算正适应度总和
def pf_sum(self, pf):
pf_total = 0
for i in range(len(pf)):
pf_total += pf[i]
return pf_total
# 正适应度变为小数
def pf_float(self, pf_total, pf):
pf_float = []
for i in range(len(pf)): # 正适应度除以适应度总数,转化为小数
pf_float.append(pf[i] / pf_total)
return pf_float
# 适应度累加,为分区做准备
def pf_div(self, pf_float):
pft_div = []
for j in range(len(pf_float)): # 将适应度转化为轮盘赌的概率
if j == 0:
pft_div.append(pf_float[j])
else:
pft_div.append(pf_float[j] + pft_div[j-1])
return pft_div
# 选择
def selection(self, pcl, pft_div):
selected_pop = [] # 挑选后的新种群
select_float = [] # 随机产生的小数
for i in range(len(pcl)): # 产生随机小数
select_float.append(random.random())
for i in range(len(pcl)): # 轮盘赌选择
j = 0
while j < len(pcl):
if select_float[i] <= pft_div[j]: # 随机小数与适应度区间对比
selected_pop.append(pcl[j])
break
else:
j += 1
return selected_pop
# 交叉
def crossover(self, selected_pop, population): # 单点交叉
new_pop = [[]]
for i in range(len(population)):
cpoint = random.randint(0, len(selected_pop[0]) - 1) # 随机生成截取点 #
while True:
spoint1 = random.randint(0, len(selected_pop) - 1)
spoint2 = random.randint(0, len(selected_pop) - 1)
if spoint1 == spoint2:
continue
else:
break
temp = [] # 染色体片段暂时存储器
temp.extend(selected_pop[spoint1][0:cpoint]) # 第i个染色体0~截取点阶段的基因存储于temp中
temp.extend(selected_pop[spoint2][cpoint:len(selected_pop[0])]) # 第i+1个染色体截取点~末端阶段的基因存储于temp中
new_pop.append(temp)
return new_pop[1:]
# 变异
def mutation(self, new_pop):
for i in range(len(new_pop)): # 对所有染色体进行有概率的变异
mpoint = random.randint(0, len(new_pop[0])-1) # 根据染色体长度,随机生成变异的位数
prandom = random.random() # 随机生成[0,1)之间的小数作为比较概率
if prandom <= self.pm:
if new_pop[i][mpoint] == 1:
new_pop[i][mpoint] = 0
else:
new_pop[i][mpoint] = 1
next_pop = new_pop
return next_pop
# 二进制转十进制
def b2d(self, value_b):
pf_d = []
for i in range(len(value_b)):
value_d = 0
for j in range(len(value_b[0])):
value_d += value_b[i][j] * math.pow(2, len(value_b[0])-1-j)
pf_d.append(value_d)
return pf_d
# 可视化
def plot(self, pcl_d_list, pf, lower_bound, upper_bound, generation, iteration):
px = []
for i in range(len(pcl_d_list)):
pxt = lower_bound + pcl_d_list[i] * (upper_bound - lower_bound) / (math.pow(2, self.chromosome_length) - 1)
px.append(pxt)
py = pf
sca = plt.scatter(px, py, s=200, lw=0, c='red', alpha=0.5)
plt.pause(0.05)
print('px', len(px))
j = generation
if j < iteration-1:
if 'sca' in locals():
sca.remove()
# 主程序
def main(self, iteration):
population = self.species_origin() # 创建种群
results = []
for i in range(iteration):
self.translation(population)
all_fitness_list = self.function(population, 0, 2*math.pi)
pf = self.positive_fitness(all_fitness_list)
pcl = self.positive_chromosome(all_fitness_list, population)
self.plot(self.translation(pcl), pf, 0, 2 * np.pi, i, iteration)
#print('pcl', pcl)
pf_total = self.pf_sum(pf)
pf_float = self.pf_float(pf_total, pf)
pft_div = self.pf_div(pf_float)
#print('pft_div', pft_div)
selected_pop = self.selection(pcl, pft_div)
new_pop = self.crossover(selected_pop, population)
next_pop = self.mutation(new_pop)
population = next_pop
results.append(pf_total)
print('The', i, 'generation pf:', pf, '\npf length', len(pf))
plt.ioff()
plt.show()
if __name__ == '__main__':
ga = GA(100, 17, 0.01)
plt.ion()
x = np.linspace(0, 2*np.pi, 100)
Fx = 2 * np.sin(x) + np.cos(x)
plt.plot(x, Fx)
plt.grid()
ga.main(500)
欢迎交流拍砖,但是瞎骂并不可取嗷~
[1]: https://blog.csdn.net/b2b160/article/details/4680853.
[2]: https://blog.csdn.net/acelit/article/details/78187715.
[3]: https://blog.csdn.net/quinn1994/article/details/80501542.
[4]: https://blog.csdn.net/m0_38101326/article/details/90642193.
[5]: https://github.com/MorvanZhou/Evolutionary-Algorithm/blob/master/tutorial-contents/Genetic%20Algorithm/Genetic%20Algorithm%20Basic.py#L72.