莫烦python:遗传算法之TSP(旅行商)代码解析

所有的笔记全在代码里,可直接看代码`

莫烦python:遗传算法之TSP(旅行商)代码解析

"""
Visualize Genetic Algorithm to find the shortest path for travel sales problem.

Visit my tutorial website for more: https://mofanpy.com/tutorials/
"""
import matplotlib.pyplot as plt
import numpy as np

N_CITIES = 20  # DNA size
CROSS_RATE = 0.1    # 交叉概率
MUTATE_RATE = 0.02  # 变异概率
POP_SIZE = 500      # 个体数目
N_GENERATIONS = 500     # 繁衍代数


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) for _ in range(pop_size)])
    #     vstack是垂直(按照行顺序)的把数组给堆叠起来
    #     permutation如果x是整数,则随机排列np.arange(x)。若果x是数组,对其复制之后再搅乱其元素。

    def translateDNA(self, DNA, city_position):  # get cities' coord in order
        line_x = np.empty_like(DNA, dtype=np.float64)
        line_y = np.empty_like(DNA, dtype=np.float64)
        # empty_like生成和已有数组相同大小,类型的数组
        # 生成的数组元素为随机数。
        for i, d in enumerate(DNA):
            # 对一个可遍历的数据对象(如列表、元组或字符串),enumerate会将该数据对象组合为一个索引序列,同时列出数据和数据下标。
            # i-->index, d-->data
            city_coord = city_position[d]
            # 找到相应的位置
            # 将相应的X,Y赋值给两列数组
            line_x[i, :] = city_coord[:, 0]
            line_y[i, :] = city_coord[:, 1]
        return line_x, line_y

    def get_fitness(self, line_x, line_y):
        # 生成一个数组,确认相邻点之间的距离
        total_distance = np.empty((line_x.shape[0],), dtype=np.float64)
        for i, (xs, ys) in enumerate(zip(line_x, line_y)):
            # i-->index, (xs, ys)-->(x,y)的位置
            total_distance[i] = np.sum(np.sqrt(np.square(np.diff(xs)) + np.square(np.diff(ys))))
        #     diff-->差分,向量化计算,举个例子--> a = [1,3,4,0] b = [2, 9, 5, 7] np.square(np.diff(a)) + np.square(np.diff(b)
        #     -->[2, 1, -4]^2 + [7, -4, 2]^2
        #     放大差别
        fitness = np.exp(self.DNA_size * 2 / 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)  # select another individual from pop
            cross_points = np.random.randint(0, 2, self.DNA_size).astype(np.bool)  # choose crossover points
            # 0-->false 1-->true
            # print(cross_points)
            # print(~cross_points)
            keep_city = parent[~cross_points]  # find the city number
            # ~在此处是非的意思
            swap_city = pop[i_, np.isin(pop[i_].ravel(), keep_city, invert=True)]
            # np.isin(a,b) 用于判定a中的元素在b中是否出现过,如果出现过返回True,否则返回False,最终结果为一个形状和a一模一样的数组。
            # 但是当参数invert被设置为True时,情况恰好相反,如果a中元素在b中没有出现则返回True,如果出现了则返回False.
            parent[:] = np.concatenate((keep_city, swap_city))
        return parent

    def mutate(self, child):
        # 在 mutate 的时候, 也是找到两个不同的 DNA 点, 然后交换这两个点就好了.
        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

    def evolve(self, fitness):
        # 选择
        pop = self.select(fitness)
        pop_copy = pop.copy()   # 备个份
        for parent in pop:  # for every parent
            # 这里parent为遍历pop,一次为其中一行,而这里的pop是从原pop中按适应度概率有放回的选出了POP_SIZE行
            # 交叉
            child = self.crossover(parent, pop_copy)
            # 变异
            child = self.mutate(child)
            parent[:] = child
            # print(parent[:])
            # print(parent)
        #     两者是一致的
        self.pop = pop


class TravelSalesPerson(object):
    def __init__(self, n_cities):
        self.city_position = np.random.rand(n_cities, 2)
        plt.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.05, "Total distance=%.2f" % total_d, fontdict={'size': 20, 'color': 'red'})
        plt.xlim((-0.1, 1.1))
        plt.ylim((-0.1, 1.1))
        plt.pause(0.01)


# 实例化对象
ga = GA(DNA_size=N_CITIES, cross_rate=CROSS_RATE, mutation_rate=MUTATE_RATE, pop_size=POP_SIZE)
# 实例化地图
env = TravelSalesPerson(N_CITIES)
for generation in range(N_GENERATIONS):
    lx, ly = ga.translateDNA(ga.pop, env.city_position)
    fitness, total_distance = ga.get_fitness(lx, ly)
    ga.evolve(fitness)
    best_idx = np.argmax(fitness)
    print('Gen:', generation, '| best fit: %.2f' % fitness[best_idx], )

    env.plotting(lx[best_idx], ly[best_idx], total_distance[best_idx])

plt.ioff()
plt.show()
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 遗传算法是一种基于生物进化原理的优化算法,可以用于求解TSP旅行问题。TSP问题是指在给定的一组城市和每对城市之间的距离下,找到一条经过每个城市一次且总距离最短的路径。 遗传算法的基本思想是将问题转化为一个个体的遗传过程,通过不断的交叉、变异和选择等操作,逐步优化种群中的个体,最终得到最优解。 具体实现过程如下: 1. 初始化种群:随机生成一定数量的个体,每个个体表示一条路径,即一组城市的访问顺序。 2. 评估适应度:计算每个个体的适应度,即路径长度。适应度越高,说明路径越短,个体越优秀。 3. 选择操作:根据适应度大小,选择一部分个体作为下一代的父代。 4. 交叉操作:对父代进行交叉操作,生成新的个体。交叉操作可以采用顺序交叉、部分映射交叉等方法。 5. 变异操作:对新生成的个体进行变异操作,引入一定的随机性。变异操作可以采用交换、插入、翻转等方法。 6. 评估适应度:计算新生成的个体的适应度。 7. 选择操作:根据适应度大小,选择一部分个体作为下一代的父代。 8. 重复步骤4-7,直到达到停止条件(如达到最大迭代次数、适应度达到一定阈值等)。 9. 输出最优解:从最终种群中选择适应度最高的个体作为最优解,即TSP问题的最短路径。 总之,遗传算法是一种有效的求解TSP问题的方法,可以通过不断的迭代优化,得到最优解。 ### 回答2: TSP问题指的是旅行问题,即在一定的时间内,旅行需要访问所有城市一次,最终回到起点,并且最小化行程距离。TSP问题作为优化问题,是计算机科学中的经典问题之一。传统的找到TSP问题最优解的求解方法是暴力枚举,但是对于较大的问题规模来说,这种方法变得非常不现实。因此,遗传算法成为了很好的解决方法。 遗传算法是一种优化算法,模拟自然界的进化过程,在解决问题时通过对“遗传信息”的编码进行选择、交叉、变异等操作从而达到全局最优或近似最优的解决方案。对于TSP问题,我们可以将遗传算法应用于其中,帮助我们找到全局最短路径。 具体实现时,我们将每个解看作一个种群中的个体,并对其进行随机编码,形成一个基因串。遗传算法会运用自然选择过程,筛选出适应度较高的基因串,构建适应度函数F。通过选择、交叉和种群变异操作,让基因串在不断迭代、进化的过程中,逐渐找到TSP的最优解。 具体实施步骤如下: 1. 确定优化目标和适应度函数:我们需要定义适当的算法来度量每个个体的适应度大小,例如,对于TSP问题,我们可以以旅行需要走的总距离作为适应度函数,离初始点越近,所需距离越短,适应度就越高。 2. 生成种群:我们通过随机选择点来构建种群,每个种群中的个体表示不同的旅游路径。 3. 选择:通过在种群中选择一部分高适应度的个体,产生新的种群。 4. 交叉:在新的种群中选择一些个体进行交叉,重新生成新的种群。 5. 变异:在新的种群中选择一部分个体进行变异操作,即对某些基因序列进行随机修改,生成新的种群。 6. 迭代:重复3-5步,多次迭代后,选择适应度最高个体作为结果输出。 Python作为一种高阶编程语言,在处理遗传算法中的求解问题方面表现突出。在实现过程中,我们可以使用Python中的numpy模块来实现矩阵计算,使用matplotlib模块对结果进行可视化处理,并结合python的其它模块,如pandas、networkx等来进行数据处理和图形展示,最终得到一个完整的TSP问题求解。 ### 回答3: 旅行问题(TSP)是一个NP难问题,它假设有一位旅行要访问n个城市,在每个城市之间都有一定的距离,要求旅行走遍所有城市且回到起点的路径是最短的。遗传算法是一种解决TSP问题的有效方法之一,Python是一门流行的编程语言,能够方便地实现遗传算法遗传算法采用生物进化的概念,将问题的解表示为一个染色体,通过模拟基因交叉、变异等操作,逐代优化解的质量。在TSP问题中,每个染色体都表示一条路径。为方便操作,可以将每个路径用城市编号表示。 首先需要构建初始种群,方法可以采用随机生成、贪心算法等。每个染色体的适应度可以用路径长度来表示,路径长度越小,适应度越高。随后进行选择操作,选择适应度高的染色体进行繁殖。为获得更多的多样性,可以采用轮盘赌算法或锦标赛选择算法。 繁殖是遗传算法的重要过程之一,主要是模拟基因交叉和变异。基因交叉分为单点交叉、多点交叉、均匀交叉等方式,可以使用随机数生成器确定交叉点和交叉方式。变异是指染色体中的一些基因改变了其值,一般用于增加种群多样性。变异的方式包括随机突变、倒位变异等。 进行多代迭代后,可以得到最优解,其中最优解的染色体表示了旅行走遍各个城市的最短路径。最后,将该染色体中编号转换为具体城市名称,即可得到最优路径。 总之,遗传算法是求解TSP问题的一种有效方法,Python语言具有简洁、高效和易于实现的特点,是实现遗传算法求解TSP问题的理想工具。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值