遗传算法解决经典运输问题

简介: 欢迎关注我的微信公众号:Python学习杂记

遗传算法是优化求解常用的一种启发式算法,其原理是模拟进化的过程,包括交叉遗传、突变、选择等方式繁衍后代,计算机通过模拟这些算子,优中选优,通过一次次迭代、繁衍,这些过程的目的就是搜索最优解。运输问题里最经典的tsp问题,是个np-难题(多一个节点,其解的可能性按指数级别上升),很难通过枚举法寻找最优解。比如有20个节点,其运输的可能性就是:20!,其结果为19位数。一般的计算机难以短时间运算出其最优解。根据主流学者的研究,遗传算法解决此类问题效果较好。(完整代码已放在本文最后。)

本文用Python编写遗传算法解决经典tsp问题的基本编程。

1.导入数据

需要建立一个两两节点的距离矩阵,距离矩阵可通过该点的位置至百度API爬取实际路程距离。

2.构建一个种群(编码并设置参数)

用不重复的1-20自然数对种群进行编码,再在起始加上0,一组数据即为一个DNA。各种参数都可以调整,后面搜索最优解的时候可以看效果调整参数。

2.构建适应度函数

适应度函数用距离的倒数来衡量,即距离越短,适应度越高,后代繁衍选址该父本的基因概率就越高。

3.轮盘筛选(算子1,优秀的父本被选择的概率高)

轮盘选择我用的是np.random.choice函数,该函数可以按照后面的概率(我用适应度来做选址的概率)来选址比较优势的父本进行繁衍。np.random.choice函数举例:

4.变异(算子2)

发生变异,一般会设置一定变异概率,概率一般设置成0.1-0.2, 变异。比如说4个节点的情况(20个节点原理一样),本次是变异如【0,1,2,3,4,0】,两个点位置交换【0,1,2,4,3,0】

5.交叉(算子3)

发生交叉,一般会设置一个交叉概率,交叉概率一般设置成0.2至0.8(tsp问题尽量不要设置的太高)。比如【0,1,2,3,4,0】交叉时1,3不变,24,按照母体【0,1,2,4,3,0】排列,则新的样本为【0,1,3,2,4,0】(20个节点原理一样)

6.进化至下一代

每一代都按照以上的方式进行循环迭代。

7.绘图

每一代结果都存储在一个数组中,后面画图看看每一代迭代效果。

8.完整代码

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
data1=pd.read_excel('datatsp.xlsx',sheet_name=0)
distance_matrix0=data1.iloc[0:,1].values #出发点到各个点的距离
distance_matrixnew=data1.iloc[1:,2:].values#经过的20个点的距离矩阵
#计算总距离的时候由0到第一个点的距离+城市总距离+最后一个城市到0的距离
best_everygeneration=[]#后面存储每一代的最优路径
lx=[]#后面存储x坐标,即迭代次数
ly=[]#存储每一代的最优值
N_CITIES = 20  # DNA size 起点不放进去,20个城市
CROSS_RATE = 0.2 #交叉系数
MUTATE_RATE = 0.01 #变异系数
POP_SIZE = 2000 #种群数
N_GENERATIONS =2000#迭代次数
class GA(object):
    def __init__(self, DNA_size, cross_rate, mutation_rate, pop_size, ):
        self.DNA_size = DNA_size
        self.cross_rate = cross_rate
        self.mutate_rate = mutation_rate
        self.pop_size = pop_size
        self.pop = np.vstack([np.random.permutation(DNA_size)+1 for _ in range(pop_size)])
    def get_fitness(self, qq):
        total_distance = np.empty((len(qq)), dtype=np.float64)
        for i,t in enumerate(qq):
            m=0
            for p in range(len(t)-1):
                m+=distance_matrixnew[t[p]-1][t[p+1]-1]
            m+=distance_matrix0[t[0]]+distance_matrix0[t[-1]]
            total_distance[i]=m
        fitness = 1/total_distance #距离的倒数做适应度,距离越小适应度越高,适应度适当放大。
        return fitness, total_distance
    def select(self, fitness):    #轮盘筛选选出较优的父母,可重复
        idx = np.random.choice(np.arange(self.pop_size), size=self.pop_size, replace=True, p=fitness / fitness.sum())
        return self.pop[idx]
    def crossover(self, parent, pop):
        if np.random.rand() < self.cross_rate:
            i_ = np.random.randint(0, self.pop_size, size=1) #随机选择一个pop的编号,后面该母体选址一部分基因
            cross_points = np.random.randint(0, 2, self.DNA_size).astype(bool)  #随机选择要发生交叉变化的点 
            keep_city = parent[~cross_points]  # find the city number
            swap_city = pop[i_, np.isin(pop[i_].ravel(), keep_city, invert=True)]#筛选出另一个母体剩下的基因(城市)
            parent[:] = np.concatenate((keep_city, swap_city))#合并交叉选择的母体
        return parent    #生成一个单一父本, 比如【0,1,2,3,4】交叉时1,3不变,024,按照母体【1,2,4,0,3】排列,则新的样本为【1,3,2,4,0】
    def mutate(self, child):
        for point in range(self.DNA_size):
            if np.random.rand() < self.mutate_rate:
                swap_point = np.random.randint(0, self.DNA_size) #随机生成变异点
                swapA, swapB = child[point], child[swap_point]  #对应两个点选出来
                child[point], child[swap_point] = swapB, swapA #交换两个点
        return child#与上一步类似,但是本次是变异如【0,1,2,3,4】,两个点位置交换【0,1,2,4,3】
    def evolve(self, fitness):    #进化至下一代
        pop0=self.pop.copy()
        pop = self.select(fitness)
        pop_copy = pop.copy()
        #print(pop0)  #看是否需要打印全部路线
        print('本次迭代最优路线',np.concatenate(([0],pop0[best_idx],[0])))
        best_everygeneration.append(np.concatenate(([0],pop0[best_idx],[0])))
        for parent in pop:  # for every parent对pop里面的每一个dna都按概率进行交叉、变异,最后生成一个新的pop
            child = self.crossover(parent, pop_copy) #交叉生成新的后代
            child = self.mutate(child) #后代中少量发生变异
            parent[:] = child #生成新的一代做为新的父母繁衍后代
        self.pop = pop
ga = GA(DNA_size=N_CITIES, cross_rate=CROSS_RATE, mutation_rate=MUTATE_RATE, pop_size=POP_SIZE)
for generation in range(1,N_GENERATIONS+1):
    fitness, total_distance = ga.get_fitness(ga.pop)
    best_idx = np.argmax(fitness)
    ga.evolve(fitness)#打印出路线
    lx.append(generation)
    ly.append(total_distance[best_idx])
    print('Gen:', generation, '| best fit: %.5f' % fitness[best_idx])
    print(total_distance[best_idx])

种群选择500个,迭代1000次,

看迭代的效果图,明显还有提高的空间。

增加种群至2000,迭代次数增加至1000,再运行一次程序。搜索最优解结果如下:其最优结果搜索到距离为690km。遗传算法需要多修改几次参数,多运行几次。因为遗传算法有可能在搜索解的过程中陷入局部最优。一般可以增加种群和迭代次数多尝试几次,也可以修改变异系数和交叉系数。


目录
相关文章
|
机器学习/深度学习 传感器 安全
【VRP问题】基于遗传算法求解带容量的车辆路径规划问题(优化目标:运输成本)附Matlab代码
【VRP问题】基于遗传算法求解带容量的车辆路径规划问题(优化目标:运输成本)附Matlab代码
|
算法
m基于PSO粒子群优化的第四方物流的作业整合算法matlab仿真,对比有代理人和无代理人两种模式下最低运输费用、代理人转换费用、运输方式转化费用和时间惩罚费用
m基于PSO粒子群优化的第四方物流的作业整合算法matlab仿真,对比有代理人和无代理人两种模式下最低运输费用、代理人转换费用、运输方式转化费用和时间惩罚费用
131 1
m基于PSO粒子群优化的第四方物流的作业整合算法matlab仿真,对比有代理人和无代理人两种模式下最低运输费用、代理人转换费用、运输方式转化费用和时间惩罚费用
|
算法 BI
m基于遗传优化算法的车辆货物运输问题matlab仿真,包括行驶距离,等待卸货时间及货损等问题
m基于遗传优化算法的车辆货物运输问题matlab仿真,包括行驶距离,等待卸货时间及货损等问题
131 0
m基于遗传优化算法的车辆货物运输问题matlab仿真,包括行驶距离,等待卸货时间及货损等问题
|
机器学习/深度学习 传感器 算法
【VRP问题】基于遗传算法结合贪婪规则求解多级仓储车辆运输问题(2E-VRP)附matlab代码
【VRP问题】基于遗传算法结合贪婪规则求解多级仓储车辆运输问题(2E-VRP)附matlab代码
|
机器学习/深度学习 传感器 算法
【路径规划-多式联运】基于遗传算法求解多式联运冷链运输成本优化问题附matlab代码
【路径规划-多式联运】基于遗传算法求解多式联运冷链运输成本优化问题附matlab代码
|
机器学习/深度学习 传感器 算法
【多式联运】基于模拟退火优化遗传算法求解多式联运运输问题(含碳政策)含Matlab代码
【多式联运】基于模拟退火优化遗传算法求解多式联运运输问题(含碳政策)含Matlab代码
|
机器学习/深度学习 传感器 搜索推荐
【路径规划-多式联运】基于遗传算法求解多式联运运输问题(考虑碳交易)附Matlab代码
【路径规划-多式联运】基于遗传算法求解多式联运运输问题(考虑碳交易)附Matlab代码
|
16天前
|
算法 安全 数据安全/隐私保护
基于game-based算法的动态频谱访问matlab仿真
本算法展示了在认知无线电网络中,通过游戏理论优化动态频谱访问,提高频谱利用率和物理层安全性。程序运行效果包括负载因子、传输功率、信噪比对用户效用和保密率的影响分析。软件版本:Matlab 2022a。完整代码包含详细中文注释和操作视频。
|
1天前
|
算法 数据挖掘 数据安全/隐私保护
基于FCM模糊聚类算法的图像分割matlab仿真
本项目展示了基于模糊C均值(FCM)算法的图像分割技术。算法运行效果良好,无水印。使用MATLAB 2022a开发,提供完整代码及中文注释,附带操作步骤视频。FCM算法通过隶属度矩阵和聚类中心矩阵实现图像分割,适用于灰度和彩色图像,广泛应用于医学影像、遥感图像等领域。
|
2天前
|
算法 调度
基于遗传模拟退火混合优化算法的车间作业最优调度matlab仿真,输出甘特图
车间作业调度问题(JSSP)通过遗传算法(GA)和模拟退火算法(SA)优化多个作业在并行工作中心上的加工顺序和时间,以最小化总完成时间和机器闲置时间。MATLAB2022a版本运行测试,展示了有效性和可行性。核心程序采用作业列表表示法,结合遗传操作和模拟退火过程,提高算法性能。