遗传算法的具体运用之TSP问题的Python解决之法


文章目录

  • 遗传算法的具体运用之TSP问题的Python解决之法
  • 前言
  • 一、基本概念简述
  • 二、算法简介
    • 2.1 遗传算法介绍
    • 2.2 基因与染色体
    • 2.3 个体编码
    • 2.4 初始群体的产生
    • 2.5 遗传算法中的物竞天择
      • 2.5.1“物竞”(适应度函数)
      • 2.5.2 “天择”(选择函数)
    • 2.6 交叉与变异
  • 三、应用问题描述
    • 1.TSP问题简述
    • 2. 数据集介绍
    • 3. 问题重述
  • 四、算法编程实现
    • 1. 导入第三方库
    • 2. 准备数据集
      • 2.1 测试数据集
      • 2.2 TSP问题数据处理与导入
    • 3. 遗传算法程序书写
    • 4. 结果展示
    • 5. 附录
  • 总结

前言

随着人工智能的不断发展,机器学习这门技术也越来越重要,很多学科都渐渐接触到机器学习的内容,本文章就经典算法——遗传算法做一个简要介绍,并以典型的TSP问题展示遗传算法的运用。本文章的程序使用Python编程语言进行书写。


提示:以下是本篇文章正文内容,下面案例可供参考

一、基本概念简述

遗传:子代与父代的某些部分具有相同或相似的形状,以保证物种的稳定性。

变异:子代与父代、子代不同个体之间存在差异性。

进化:生物在演化过程中,物种逐渐适应环境,淘汰了不适应环境的物种,留下了能够适应环境的优良物种,这种现象称为进化。

二、算法简介

2.1 遗传算法介绍

遗传算法是1975年由密切根大学的J.Holland提出的,它是一种通过模拟自然进化过程寻找最优解的方法。例如,可以利用它求解函数的最值问题。

2.2 基因与染色体

在遗传算法中,我们首先需要将一个现实问题转化为具体的函数表达式,我们称着一过程为“数学建模”,该问题的一个可行解称为一条“染色体”

例如:对于不等式x + y + z < 60, [1, 2, 3], [5, 7, 9], [8, 2, 5]都是这个不等式函数的可行解,每一个可行解在遗传算法中被称为染色体,每一个可行解中的每一个元素称为染色体上的一个基因。

2.3 个体编码

遗传算法的运算对象是表示格提的符号串,需要对“数学建模”后的变量x,y,z编码为一种符号串。常见的编码方式为使用无符号二进制数来表示。

2.4 初始群体的产生

遗传算法是对群体进行的进化操作,需要准备一些表示起始搜索点的起始群体数据。

例如,群体的规模大小为4,即群体由4个个体组成,每个个体可以通过随机方法生成。例如:011, 010, 100, 110。

2.5 遗传算法中的物竞天择

2.5.1“物竞”(适应度函数)

                能够适应环境的概率==>适应度函数

遗传算法中以个体适应度的大小来评定各个个体的优劣程度,从而决定其遗传机会的大小。

2.5.2 “天择”(选择函数)

在自然界中,越适应的个体就越有可能繁殖后代。但也不是适应度越高就肯定后代越多,只能是从概率上来说是更多。例如,日常生活中可能见到的转盘游戏。

2.6 交叉与变异

交叉:
父: 00110101
母: 01110001
子: 00110001

变异:
父: 00110101
母: 01110001
子: 10110001

复制:每次进化中,为了保留上一代优良的染色体,需要将上一代中适应度最高的几条染色体直接原封不动地复制给下一代。

三、应用问题描述

1.TSP问题简述

TSP,(全称 Travelling salesman problem)。旅行商客问题主要解决的是最佳路径规划问题。针对这一类典型问题,常用的优化算法蚁群算法、模拟退火算法、遗传算法等等。本文采用遗传算法进行优化。

2. 数据集介绍

TSP问题根据问题的不同所需要的数据集也不同,为降低难度进行理解,本次实验采用的是二维数据集,即通过两个数值表示一个城市点的坐标。提升一点难度可以考虑三维模式,再难一点就可以考虑球坐标点,这样就需要读者通过坐标转化关系式进行建模。针对这几种数据集,无论是哪一种,最终在使用遗传算法时都是十分类似的,通常都是使用距离作为评判标准和优化目标。

本次所采用的数据集部分截图展示如下:

3. 问题重述

本次实验所要解决的问题是对TSP数据进行处理,构建合适的遗传算法程序和评判指标,寻找出最优的路径。

四、算法编程实现

1. 导入第三方库

本次实验主要涉及到数据处理与可视化第三方库numpy和matplotlib,导入第三方库具体程序如下:

import numpy as np
import matplotlib.pyplot as plt

2. 准备数据集

2.1 测试数据集

本次实验首先随机生成10个地址,对编写的程序做检验,具体程序如下:

class TSP(object):def __init__(self, citys):data = np.random.rand(citys, 2)self.city_position = data

2.2 TSP问题数据处理与导入

常规TSP问题数据集导入与预处理

data = np.loadtxt("data12_1.txt")
# 将导入的数据集转换成(x,y)的形式
data1 = np.array(data).reshape(-1, 2)

通过TSP类导入数据

class TSP(object):def __init__(self, data1):self.city_position = data1env = TSP(data1 = data1)

在TSP类程序里,除了定义了数据集,同时也定义了图像绘制程序,可视化的显示数据处理的过程。具体程序展示如下:

class TSP(object):def plotting(self, lx, ly, total_d):plt.cla()plt.scatter(self.city_position[:, 0].T, self.city_position[:, 1].T, s=100, c='k')plt.plot(lx.T, ly.T, 'r-')plt.text(-0.05, -0.1, "Total distance=%.2f"%total_d, fontdict={'size': 20, 'color': 'red'})# plt.xlim(0.1, 1.1)# plt.ylim(-0.15, 1.1)plt.pause(0.01)

3. 遗传算法程序书写

class GA(object):def __init__(self, citys, pc, pm, popsize):self.citys = citysself.pc = pcself.pm = pmself.popsize = popsize# 生成种群,DNA序列为0到50的随机序列self.pop = np.vstack([np.random.permutation(citys) for _ in range(popsize)])# 将种群中排列好的序列横纵坐标分别提取出来def translateDNA(self, DNA, city_position):lineX = np.empty_like(DNA, dtype=np.float64)lineY = np.empty_like(DNA, dtype=np.float64)for i, d in enumerate(DNA):city_coord = city_position[d]lineX[i, :] = city_coord[:, 0]lineY[i, :] = city_coord[:, 1]return lineX, lineY# 求取距离适应度函数def getFitness(self, lineX, lineY):totalDis = np.empty((lineX.shape[0],), dtype=np.float64)for i, (xval, yval) in enumerate(zip(lineX, lineY)):totalDis[i] = np.sum(np.sqrt(np.square(np.diff(xval)) + np.square(np.diff(yval))))fitness = np.exp(self.citys * 2 / totalDis)return fitness, totalDis# 定义选择函数def selection(self, fitness):idx = np.random.choice(np.arange(self.popsize), size=self.popsize, replace=True, p=fitness/fitness.sum())return self.pop[idx]# 交叉函数def crossover(self, parent, pop):if np.random.rand() < self.pc:i = np.random.randint(0, self.citys, size=1)cross_points =np.random.randint(0, 2, self.citys).astype(np.bool)keep_city = parent[~cross_points]swap_city = pop[i, np.isin(pop[i].ravel(), keep_city, invert=True)]parent[:] = np.concatenate((keep_city, swap_city))return parent# 变异函数def mutation(self, child):for point in range(self.citys):if np.random.rand() < self.pm:swap_point = np.random.randint(0, self.citys)swapa, swapb = child[point], child[swap_point]child[point], child[swap_point] = swapa, swapbreturn child# 进化函数def evolve(self, fitness):pop = self.selection(fitness)pop_copy = pop.copy()for parent in pop:child = self.crossover(parent, pop_copy)child = self.mutation(child)parent[:] = childself.pop = pop

4. 结果展示

测试程序结果展示如下:

TSP问题展示结果如下:


5. 附录

测试程序:

import numpy as np
import matplotlib.pyplot as plt# data = np.loadtxt("data12_1.txt")
# data1 = np.array(data).reshape(-1, 2)
citys = 10
pc = 0.23
pm = 0.037
popsize = 50
iternum = 200class GA(object):def __init__(self, citys, pc, pm, popsize):self.citys = citysself.pc = pcself.pm = pmself.popsize = popsize# 生成种群,DNA序列为0到50的随机序列self.pop = np.vstack([np.random.permutation(citys) for _ in range(popsize)])# 将种群中排列好的序列横纵坐标分别提取出来def translateDNA(self, DNA, city_position):lineX = np.empty_like(DNA, dtype=np.float64)lineY = np.empty_like(DNA, dtype=np.float64)for i, d in enumerate(DNA):city_coord = city_position[d]lineX[i, :] = city_coord[:, 0]lineY[i, :] = city_coord[:, 1]return lineX, lineY# 求取距离适应度函数def getFitness(self, lineX, lineY):totalDis = np.empty((lineX.shape[0],), dtype=np.float64)for i, (xval, yval) in enumerate(zip(lineX, lineY)):totalDis[i] = np.sum(np.sqrt(np.square(np.diff(xval)) + np.square(np.diff(yval))))fitness = np.exp(self.citys * 2 / totalDis)return fitness, totalDis# 定义选择函数def selection(self, fitness):idx = np.random.choice(np.arange(self.popsize), size=self.popsize, replace=True, p=fitness/fitness.sum())return self.pop[idx]# 交叉函数def crossover(self, parent, pop):if np.random.rand() < self.pc:i = np.random.randint(0, self.citys, size=1)cross_points =np.random.randint(0, 2, self.citys).astype(np.bool)keep_city = parent[~cross_points]swap_city = pop[i, np.isin(pop[i].ravel(), keep_city, invert=True)]parent[:] = np.concatenate((keep_city, swap_city))return parent# 变异函数def mutation(self, child):for point in range(self.citys):if np.random.rand() < self.pm:swap_point = np.random.randint(0, self.citys)swapa, swapb = child[point], child[swap_point]child[point], child[swap_point] = swapa, swapbreturn child# 进化函数def evolve(self, fitness):pop = self.selection(fitness)pop_copy = pop.copy()for parent in pop:child = self.crossover(parent, pop_copy)child = self.mutation(child)parent[:] = childself.pop = popclass TSP(object):def __init__(self, citys):# self.data = np.loadtxt("data12_1.txt")# self.data1 = np.array(self.data).reshape(-1, 2)# self.x = []# self.y = []# for i in range(citys):#     self.x.append(self.data1[i][0])#     self.y.append(self.data1[i][1])# data = [[3, 2],#         [6, 8],#         [9, 5],#         [10, 20],#         [18, 13],#         [6, 9],#         [9, 11],#         [3, 5],#         [7, 9],#         [8, 3]]data = np.random.rand(citys, 2)self.city_position = dataplt.ion()def plotting(self, lx, ly, total_d):plt.cla()plt.scatter(self.city_position[:, 0].T, self.city_position[:, 1].T, s=100, c='k')plt.plot(lx.T, ly.T, 'r-')plt.text(-0.05, -0.1, "Total distance=%.2f"%total_d, fontdict={'size': 20, 'color': 'red'})# plt.xlim(0.1, 1.1)# plt.ylim(-0.15, 1.1)plt.pause(0.01)if __name__ == "__main__":env = TSP(citys=citys)ga = GA(citys=citys, pc=pc, pm=pm, popsize=popsize)for gen in range(iternum):lx, ly = ga.translateDNA(ga.pop, env.city_position)fitness, total_distance = ga.getFitness(lx, ly)ga.evolve(fitness)best_idx = np.argmax(fitness)print("Gen:", gen, "| best fit: %.2f"%fitness[best_idx],)env.plotting(lx[best_idx], ly[best_idx], total_distance[best_idx])plt.ioff()plt.show()

实验程序:

# 导入第三方库
import numpy as np
import matplotlib.pyplot as pltdata = np.loadtxt("data12_1.txt")
data1 = np.array(data).reshape(-1, 2)
citys = len(data1)
pc = 0.39
pm = 0.01
popsize = 20
iternum = 2000class GA(object):def __init__(self, citys, pc, pm, popsize):self.citys = citysself.pc = pcself.pm = pmself.popsize = popsize# 生成种群,DNA序列为0到50的随机序列self.pop = np.vstack([np.random.permutation(citys) for _ in range(popsize)])# 将种群中排列好的序列横纵坐标分别提取出来def translateDNA(self, DNA, city_position):lineX = np.empty_like(DNA, dtype=np.float64)lineY = np.empty_like(DNA, dtype=np.float64)for i, d in enumerate(DNA):city_coord = city_position[d]lineX[i, :] = city_coord[:, 0]lineY[i, :] = city_coord[:, 1]return lineX, lineY# 求取距离适应度函数def getFitness(self, lineX, lineY):totalDis = np.empty((lineX.shape[0],), dtype=np.float64)for i, (xval, yval) in enumerate(zip(lineX, lineY)):totalDis[i] = np.sum(np.sqrt(np.square(np.diff(xval)) + np.square(np.diff(yval))))fitness = np.exp(self.citys * 2 / totalDis)return fitness, totalDis# 定义选择函数def selection(self, fitness):idx = np.random.choice(np.arange(self.popsize), size=self.popsize, replace=True, p=fitness/fitness.sum())return self.pop[idx]# 交叉函数def crossover(self, parent, pop):if np.random.rand() < self.pc:i = np.random.randint(0, self.citys, size=1)cross_points =np.random.randint(0, 2, self.citys).astype(np.bool)keep_city = parent[~cross_points]swap_city = pop[i, np.isin(pop[i].ravel(), keep_city, invert=True)]parent[:] = np.concatenate((keep_city, swap_city))return parent# 变异函数def mutation(self, child):for point in range(self.citys):if np.random.rand() < self.pm:swap_point = np.random.randint(0, self.citys)swapa, swapb = child[point], child[swap_point]child[point], child[swap_point] = swapa, swapbreturn child# 进化函数def evolve(self, fitness):pop = self.selection(fitness)pop_copy = pop.copy()for parent in pop:child = self.crossover(parent, pop_copy)child = self.mutation(child)parent[:] = childself.pop = popclass TSP(object):def __init__(self, data1):# self.data = np.loadtxt("data12_1.txt")# self.data1 = np.array(self.data).reshape(-1, 2)# self.x = []# self.y = []# for i in range(citys):#     self.x.append(self.data1[i][0])#     self.y.append(self.data1[i][1])self.city_position = data1plt.ion()def plotting(self, lx, ly, total_d):plt.cla()plt.scatter(self.city_position[:, 0].T, self.city_position[:, 1].T, s=100, c='k')plt.plot(lx.T, ly.T, 'r-')plt.text(-0.05, -0.1, "Total distance=%.2f"%total_d, fontdict={'size': 20, 'color': 'red'})# plt.xlim(0.1, 1.1)# plt.ylim(-0.15, 1.1)plt.pause(0.01)if __name__ == "__main__":env = TSP(data1=data1)ga = GA(citys=citys, pc=pc, pm=pm, popsize=popsize)for gen in range(iternum):lx, ly = ga.translateDNA(ga.pop, env.city_position)fitness, total_distance = ga.getFitness(lx, ly)ga.evolve(fitness)best_idx = np.argmax(fitness)print("Gen:", gen, "| best fit: %.2f"%fitness[best_idx],)env.plotting(lx[best_idx], ly[best_idx], total_distance[best_idx])plt.ioff()plt.show()

提示:注释部分的程序为调试时所用,读者复现时可以做一定的参考。


总结

本次实验基本利用遗传算法解决了TSP问题,但是在实验中也发现了很多不足之处。

首先,交叉和变异值的选取没有合理的定义规范,对于后期应对复杂问题具有一定的挑战性。

其次,由于遗传算法存在随机性,最优结果的确定是一个概率问题,由于随机性的存在,导致程序运行中可能已经存在了最优解,但是程序没有中断,可能会导致最后的结果次优,或更差。

最后,将数据不断扩大可以发现,程序的运行效率降低许多的同时寻找到的结果离最优解也差得越来越多。

针对以上存在的问题,也欢迎读者见谅并提出指导性建议,共同探讨和完善。


Ps:该文章由本人和另一博主共同完成。

遗传算法的运用(Python版)相关推荐

  1. 遗传算法解决旅行商问题(Python版)

    完整代码点这里 遗传算法解决旅行商问题(Python版) 一.问题描述 TSP问题(Travelling Salesman Problem)即旅行商问题,又译为旅行推销员问题.货郎担问题,是数学领域中 ...

  2. 遗传算法(python版)

    遗传算法(python版) 1.基本概念 遗传算法(GA)是最早由美国Holland教授提出的一种基于自然界的"适者生存,优胜劣汰"基本法则的智能搜索算法.该法则很好地诠释了生物进 ...

  3. Python版自动组卷评卷考试系统,具有考试定时、自动组卷、客观题自动判卷、自动评分和考试界面设计功能

    一.实验项目名称: 自动组卷评卷考试系统 二.实验内容 用Python语言编程实现自动组卷评卷考试系统,软件主要功能包括:从题库中随机抽取试题自动组成试卷(满分100分):实现考生考试答题操作界面:实 ...

  4. 算法(Python版)|156Kstars|神级项目-(1)The Algorithms - Python简介

    文章目录 算法(Python版) 项目地址 项目概况 说明 参与入门 社区频道 算法列表 Arithmetic Analysis 算术分析 Audio Filters 音频过滤器 Backtracki ...

  5. 【Leetcode】刷题之路3(python版)

    回溯专题 1.回溯算法的本质是n叉树的深度优先搜索,同时,需要注意剪枝减少复杂度. 2.回溯算法三部曲 确定参数和返回值 回溯函数终止条件 单层循环 3.回溯法思路 回溯法是一种算法思想,而递归是一种 ...

  6. 统计学习圣经!经典教材《统计学习导论》Python版

    ↑↑↑关注后"星标"Datawhale 每日干货 & 每月组队学习,不错过 Datawhale干货 编辑:张倩,来源:机器之心 <统计学习导论>很经典,但习题用 ...

  7. python数据结构与算法分析_数据结构与算法(Python版)

    为什么研究数据结构与算法 本周带大家进入Python版数据结构与算法的学习.想必大家都听过"算法"一词,算法的学习对编程者来说是至关重要的.首先我们先了解一下为什么要研究数据结构与 ...

  8. 经典教材《统计学习导论》现在有了Python版

    来源:机器之心 本文约1000字,建议阅读5分钟 <统计学习导论>很经典,但用的是 R 语言,没关系,这里有份 Python 版习题实现. 斯坦福经典教材<The Element o ...

  9. 赞!经典教材《统计学习导论》终于有Python版了

    <统计学习导论>是数据科学家中最受欢迎的书籍之一,旨在介绍机器学习算法背后的概念,但这本书的习题都是用R语言实现的,这对于主要使用 Python 语言的机器学习研究者来说不太友好. 为了解 ...

最新文章

  1. 计算机接口与通信技术考试题,全国2010年10月自学考试计算机通信接口技术试题...
  2. 你能说出 Kafka 这些原理吗
  3. 新外贸110%加速度,阿里巴巴国际站力推百亿投资计划
  4. SQLServer多实例更改默认实例
  5. 后退键无效 html,javascript – Cordova – window.history.back()不支持iOS 9中的HTML后退按钮...
  6. 微博深度学习平台架构和实践
  7. JavaSE基础复习总结
  8. 注解RequestMapping中的URI路径最前面到底需不需要加斜线?
  9. windows API 串口编程参考
  10. Menelaus定理与证明
  11. 699 - The Falling Leaves
  12. WIN2016群集存储
  13. spss分析方法-判别分析
  14. android service开启前台通知
  15. allure企业级定制报告
  16. 国外天气预报接口 全球热门城市7天天气预报接口
  17. GitHub 标星 4.9k,李笑来开源的英语学习课
  18. 判断两条线段是否相交 java_判断两个线段是否相交02
  19. python中print()换行的问题
  20. 开发板搭建简单的Web服务器

热门文章

  1. Java中常用的API
  2. 普林斯顿大学颜宁教授宣布全职加盟深圳医学科学院
  3. ListView的长按事件和点击事件冲突的解决办法
  4. Random与ThreadLocalRandom 解析
  5. document在方法外获取对象无法获取数据
  6. RHCS+Conga+iSCSI+CLVM+GFS实现Web服务的共享存储HA集群
  7. DHCP协议理论解析与抓包实践
  8. maven项目中,使用pom文件引入自定义jar包
  9. 深入浅出原核基因表达调控(乳糖操纵子、色氨酸操纵子)
  10. ssm 上传图片到mysql_MySQL+SSM+Ajax上传图片问题的分析(图)