纯个人学习记录,如有问题,请大佬指出。
一、遗传算法简介
遗传算法是一种通过模拟自然进化过程来求解最优解的通用型优化算法。它可以用于求解各种优化问题,如函数最优化、组合优化、约束优化等。遗传算法常用于复杂的优化问题中,其搜索范围广,搜索能力强,但对于评估函数的要求很低。
遗传算法的基本流程包括:初始化种群、评估种群适应度、选择操作、交叉操作、变异操作等步骤。下面是一个典型的遗传算法流程:
1. 初始化种群
从定义域随机产生一定数量的初始解,作为第一代种群。例如,若最小值是 0 ,最大值是 100,那就随机产生一定数量的 0 至 100 之间的数作为初始解。
2. 评估种群适应度
将初始解和后续进化得到的所有解带入目标函数中,根据函数值(适应度)来评估每个个体的表现。
3. 选择操作
选择操作的目的是根据种群中个体的适应度来选择优秀的个体作为繁殖的父(母)个体,从而产生新一代种群。选择操作一般采用轮盘赌选择或锦标赛选择。
4. 交叉操作
随机选择两个个体,进行基因交叉操作,从而交换两个个体的一部分染色体,产生新的个体。
5. 变异操作
在新一代种群中,对一部分个体进行适当的变异操作,比如改变一个或多个基因的值。
6. 替换操作
将新一代的个体与上一代的个体进行比较,选择更好的个体进入下一代种群。
7. 结束条件
循环迭代执行以上几个步骤,直到满足结束条件为止,通常会设置最大迭代次数或达到一定的收敛精度等条件来终止程序。
二、0-1背包问题
对于 0-1 背包问题,遗传算法可以如下实现:
1. 初始化种群
随机产生一定数量(例如 30 个)的初始个体。每个个体是表示物品选中状态的二进制编码,例如:00101010010010110110110 表示选中第 2、4、5、7、9、11 和 12 号物品,其它物品不选中。
# 初始化种群,popsize代表种群个数,n代表基因长度(几个物件)
def init(popsise, n):
population = [] # 生成列表,存储种群中的每个个体
for i in range(popsise):
temporary = []
for j in range(n):
temporary.append(random.randint(0, 1)) # 生成一个0到1的随机数,转化为字符串加入到pop字符串的尾部
population.append(temporary)
# print(population)
return population
2. 计算个体适应度
将每个候选个体代入 0-1 背包问题的模型中,计算其对应的价值。将价值作为个体的适应度,以便进行选择操作。
# 计算种群中每个个体此时所代表的解的重量weight和效益profit
def computeFitness(population, weight, profit):
# print(population)
total_weight = [] # 用来存放每个个体的重量weight
total_profit = [] # 用来存放每个个体的价值profit
# print(population, weight, profit)
for i in range(len(population)):
temporary1 = 0
temporary2 = 0
# weight = [5, 7, 9, 8, 4, 3, 10, 14, 13, 9, 15, 11, 1, 15, 14, 18, 17, 16, 4, 18] # 重量
# profit = [10, 8, 15, 9, 6, 5, 20, 10, 13, 1, 5, 7, 9, 18, 4, 3, 10, 14, 13, 19] # 价值
for j in range(len(population[i])):
if population[i][j] == 1:
temporary1 += weight[j]
temporary2 += profit[j]
total_weight.append(temporary1)
total_profit.append(temporary2)
# print(total_weight, total_profit)
return total_weight, total_profit
3. 选择操作
根据个体适应度选择某些个体参与下一代的繁殖。常见的选择方法有轮盘赌选择、锦标赛选择等。轮盘赌选择中,每个个体的被选中概率与其适应度成正比;锦标赛选择中,随机选择一些个体进行比赛,然后选出表现最好的个体作为参与繁殖的个体。
# 筛选符合条件的
def select(population, weight_limit, total_weight, total_profit): # weight_limit为背包限制
w = []
p = []
m = 0
new_population = []
for i in range(len(total_weight)):
if total_weight[i] < weight_limit:
w.append(total_weight[i])
p.append(total_profit[i])
new_population.append(population[i])
else:
m += 1
while m > 0:
i = random.randint(0, len(new_population) - 1)
temp = new_population[i]
new_population.append(temp)
w.append(w[i])
p.append(p[i])
m -= 1
population = new_population
return population, w, p
# 选择策略(轮盘赌选择)
def roulettewheel(popsize, population, total_profit):
sum_profit = 0
p = [] # 存放每个个体的选择概率
temp = 0
for i in range(len(total_profit)):
sum_profit += total_profit[i] # 计算个体适应值之和
for i in range(len(total_profit)):
q = total_profit[i] / sum_profit # 计算每个个体的选择概率
p.append(temp + q)
temp += q
# print(p)
new_population = []
while len(new_population) < popsize:
select_p = random.uniform(0, 1)
if select_p <= p[0]:
new_population.append(population[0])
elif p[1] <= select_p <= p[2]:
new_population.append(population[2])
for i in range(3, len(p)):
if p[i - 1] < select_p <= p[i]:
new_population.append(population[i])
population = new_population
# print(len(population))
return population
4. 交叉操作
随机选择两个个体,并在二进制编码中选择一个交叉点,交换两个个体交叉点的左右部分,从而产生两个新的个体。
# 随机交配
def corssover(population, pc):
i = 0
new_population = population[:] # 复制种群
while i < len(population):
if (random.uniform(0, 1) < pc):
mother_index = random.randint(0, len(population) - 1)
father_index = random.randint(0, len(population) - 1)
cpoint = random.randint(0, len(population[0]) - 1)
if father_index != mother_index:
temp11 = population[father_index][:cpoint]
temp12 = population[father_index][cpoint:]
temp21 = population[mother_index][cpoint:]
temp22 = population[mother_index][:cpoint]
child1 = temp21 + temp11
child2 = temp12 + temp22
new_population[father_index] = child1
new_population[mother_index] = child2
i += 1
population = new_population
return population
5. 变异操作
对于一些被选中的个体,随机地翻转一些二进制位,从而产生新的个体。变异操作能够避免所有个体都朝着同一个方向进化,从而提高算法的探索能力。
# 变异
def mutation(population, pm):
temporary = []
for i in range(len(population)):
p = random.uniform(0, 1)
if p < pm:
j = 0
while (j < 2):
mpoint = random.randint(0, len(population[0]) - 1)
if population[i][mpoint] == 0:
population[i][mpoint] = 1
else:
population[i][mpoint] = 0
j += 1
temporary.append(population[i])
else:
temporary.append(population[i])
population = temporary
return population
6. 更新种群
将选择、交叉和变异所产生的新个体和部分旧个体组成新一代种群。然后,计算每个个体的适应度,判断是否达到终止条件,如果没有则返回步骤 3。
7. 输出最优解
循环结束后,输出种群中具有最大适应度的个体,即为问题的最优解。
def main():
pm = 0.2 # 变异概率
pc = 0.8 # 交叉概率
N = 30 # 迭代次数
popsize = 20 # 初始种群个数
n = 10 # 10个物件
weight = [5, 7, 9, 8, 4, 3, 10, 14, 13, 12] # 重量
profit = [10, 8, 15, 9, 6, 5, 20, 10, 13, 16] # 价值
weight_limit = 100 # 背包限制
iter = 0 # 迭代次数(指针计数)
population = init(popsize, n)
while iter < N:
iter = iter + 1
print("——————————————————————————————————————————————————————————————————————————————————————————————————————")
print(f'第{iter}代')
print(f'第{iter}代群体为:', population)
# 计算每一代每个个体的适应度值
total_weight, total_profit = computeFitness(population, weight, profit)
print('weight为:', total_weight)
print('profit为:', total_profit)
# 进行筛选,筛选weight是否大于weight_limit
s_pop, s_w, s_p, = select(population, weight_limit, total_weight, total_profit)
print(f'筛选后的群种为:{s_pop}')
print(f'筛选后的weight为:{s_w}')
print(f'筛选后的profit为:{s_p}')
# 进行轮盘赌选择
population = roulettewheel(popsize, s_pop, s_p)
print('选择后的种群为:', population)
# 交叉操作
population = corssover(population, pc)
print('交叉后的群体为:', population)
# 变异操作
population = mutation(population, pm)
print('变异后的群体为:', population)
print('-------------------------------' * 2)
# 输出全局最优个体染色体,最优个体适应值(这里在重新调用一遍,目的是把最后一代的个体也进行选择后再进行比较)
total_weight, total_profit = computeFitness(population, weight, profit)
s_pop, s_w, s_p, = select(population, weight_limit, total_weight, total_profit) # 筛选weight是否大于weight_limit
global best_individual, best_individual_pop
global best_fitness, best_fitness_pop
global best_weight, best_weight_pop
m = 0
for i in range(len(population)):
if best_fitness < s_p[i]:
best_fitness = s_p[i]
best_weight = s_w[i]
m = i
best_individual_pop = population
best_individual = population[m]
best_weight_pop = s_w
best_fitness_pop = s_p
print("全局最优个体种群为:", best_individual_pop)
print("全局最优个体为:", best_individual)
print("全局最优个体种群价值为:", best_fitness_pop)
print("全局最优个体价值为:", best_fitness)
print("全局最优个体种群重量为:", best_weight_pop)
print("全局最优个体重量为:", best_weight)
8、全部代码如下
import random
global best_individual, best_individual_pop
global best_fitness, best_fitness_pop
global best_weight, best_weight_pop
best_fitness = 0
best_fitness_pop = []
best_weight = 0
best_weight_pop = []
best_individual = []
best_individual_pop = []
# 初始化种群,popsize代表种群个数,n代表基因长度(几个物件)
def init(popsise, n):
population = [] # 生成列表,存储种群中的每个个体
for i in range(popsise):
temporary = []
for j in range(n):
temporary.append(random.randint(0, 1)) # 生成一个0到1的随机数,转化为字符串加入到pop字符串的尾部
population.append(temporary)
# print(population)
return population
# 计算种群中每个个体此时所代表的解的重量weight和效益profit
def computeFitness(population, weight, profit):
# print(population)
total_weight = [] # 用来存放每个个体的重量weight
total_profit = [] # 用来存放每个个体的价值profit
# print(population, weight, profit)
for i in range(len(population)):
temporary1 = 0
temporary2 = 0
# weight = [5, 7, 9, 8, 4, 3, 10, 14, 13, 9, 15, 11, 1, 15, 14, 18, 17, 16, 4, 18] # 重量
# profit = [10, 8, 15, 9, 6, 5, 20, 10, 13, 1, 5, 7, 9, 18, 4, 3, 10, 14, 13, 19] # 价值
for j in range(len(population[i])):
if population[i][j] == 1:
temporary1 += weight[j]
temporary2 += profit[j]
total_weight.append(temporary1)
total_profit.append(temporary2)
# print(total_weight, total_profit)
return total_weight, total_profit
# 筛选符合条件的
def select(population, weight_limit, total_weight, total_profit): # weight_limit为背包限制
w = []
p = []
m = 0
new_population = []
for i in range(len(total_weight)):
if total_weight[i] < weight_limit:
w.append(total_weight[i])
p.append(total_profit[i])
new_population.append(population[i])
else:
m += 1
while m > 0:
i = random.randint(0, len(new_population) - 1)
temp = new_population[i]
new_population.append(temp)
w.append(w[i])
p.append(p[i])
m -= 1
population = new_population
return population, w, p
# 选择策略(轮盘赌选择)
def roulettewheel(popsize, population, total_profit):
sum_profit = 0
p = [] # 存放每个个体的选择概率
temp = 0
for i in range(len(total_profit)):
sum_profit += total_profit[i] # 计算个体适应值之和
for i in range(len(total_profit)):
q = total_profit[i] / sum_profit # 计算每个个体的选择概率
p.append(temp + q)
temp += q
# print(p)
new_population = []
while len(new_population) < popsize:
select_p = random.uniform(0, 1)
if select_p <= p[0]:
new_population.append(population[0])
elif p[1] <= select_p <= p[2]:
new_population.append(population[2])
for i in range(3, len(p)):
if p[i - 1] < select_p <= p[i]:
new_population.append(population[i])
population = new_population
# print(len(population))
return population
# 随机交配
def corssover(population, pc):
i = 0
new_population = population[:] # 复制种群
while i < len(population):
if (random.uniform(0, 1) < pc):
mother_index = random.randint(0, len(population) - 1)
father_index = random.randint(0, len(population) - 1)
cpoint = random.randint(0, len(population[0]) - 1)
if father_index != mother_index:
temp11 = population[father_index][:cpoint]
temp12 = population[father_index][cpoint:]
temp21 = population[mother_index][cpoint:]
temp22 = population[mother_index][:cpoint]
child1 = temp21 + temp11
child2 = temp12 + temp22
new_population[father_index] = child1
new_population[mother_index] = child2
i += 1
population = new_population
return population
# 变异
def mutation(population, pm):
temporary = []
for i in range(len(population)):
p = random.uniform(0, 1)
if p < pm:
j = 0
while (j < 2):
mpoint = random.randint(0, len(population[0]) - 1)
if population[i][mpoint] == 0:
population[i][mpoint] = 1
else:
population[i][mpoint] = 0
j += 1
temporary.append(population[i])
else:
temporary.append(population[i])
population = temporary
return population
def main():
pm = 0.2 # 变异概率
pc = 0.8 # 交叉概率
N = 30 # 迭代次数
popsize = 20 # 初始种群个数
n = 10 # 10个物件
weight = [5, 7, 9, 8, 4, 3, 10, 14, 13, 12] # 重量
profit = [10, 8, 15, 9, 6, 5, 20, 10, 13, 16] # 价值
weight_limit = 100 # 背包限制
iter = 0 # 迭代次数(指针计数)
population = init(popsize, n)
while iter < N:
iter = iter + 1
print("——————————————————————————————————————————————————————————————————————————————————————————————————————")
print(f'第{iter}代')
print(f'第{iter}代群体为:', population)
# 计算每一代每个个体的适应度值
total_weight, total_profit = computeFitness(population, weight, profit)
print('weight为:', total_weight)
print('profit为:', total_profit)
# 进行筛选,筛选weight是否大于weight_limit
s_pop, s_w, s_p, = select(population, weight_limit, total_weight, total_profit)
print(f'筛选后的群种为:{s_pop}')
print(f'筛选后的weight为:{s_w}')
print(f'筛选后的profit为:{s_p}')
# 进行轮盘赌选择
population = roulettewheel(popsize, s_pop, s_p)
print('选择后的种群为:', population)
# 交叉操作
population = corssover(population, pc)
print('交叉后的群体为:', population)
# 变异操作
population = mutation(population, pm)
print('变异后的群体为:', population)
print('-------------------------------' * 2)
# 输出全局最优个体染色体,最优个体适应值(这里在重新调用一遍,目的是把最后一代的个体也进行选择后再进行比较)
total_weight, total_profit = computeFitness(population, weight, profit)
s_pop, s_w, s_p, = select(population, weight_limit, total_weight, total_profit) # 筛选weight是否大于weight_limit
global best_individual, best_individual_pop
global best_fitness, best_fitness_pop
global best_weight, best_weight_pop
m = 0
for i in range(len(population)):
if best_fitness < s_p[i]:
best_fitness = s_p[i]
best_weight = s_w[i]
m = i
best_individual_pop = population
best_individual = population[m]
best_weight_pop = s_w
best_fitness_pop = s_p
print("全局最优个体种群为:", best_individual_pop)
print("全局最优个体为:", best_individual)
print("全局最优个体种群价值为:", best_fitness_pop)
print("全局最优个体价值为:", best_fitness)
print("全局最优个体种群重量为:", best_weight_pop)
print("全局最优个体重量为:", best_weight)
if __name__ == "__main__":
main()