进化计算原理和实现(遗传算法)

简介

遗传算法(Genetic Algorithm,GA)最早是由美国的 John holland于20世纪70年代提出,该算法是根据大自然中生物体进化规律而设计提出的。是模拟达尔文生物进化论的自然选择和遗传学机理的生物进化过程的计算模型,是一种通过模拟自然进化过程搜索最优解的方法。该算法通过数学的方式,利用计算机仿真运算,将问题的求解过程转换成类似生物进化中的染色体基因的交叉、变异等过程。在求解较为复杂的组合优化问题时,相对一些常规的优化算法,通常能够较快地获得较好的优化结果。遗传算法已被人们广泛地应用于组合优化、机器学习、信号处理、自适应控制和人工生命等领域。

由来

在这里插入图片描述

遗传算法

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

基本代码实现

代码

项目代码结构
在这里插入图片描述

基本代码和数据集

import random
import math
import numpy as np
import matplotlib.pyplot as plt


class GA(object):
    def __init__(self, num_city, num_total, iteration, data):
        self.num_city = num_city
        self.num_total = num_total
        self.scores = []
        self.iteration = iteration
        self.location = data
        self.ga_choose_ratio = 0.2
        self.mutate_ratio = 0.05
        # fruits中存每一个个体是下标的list
        self.dis_mat = self.compute_dis_mat(num_city, data)
        self.fruits = self.greedy_init(self.dis_mat,num_total,num_city)
        # 显示初始化后的最佳路径
        scores = self.compute_adp(self.fruits)
        sort_index = np.argsort(-scores)
        init_best = self.fruits[sort_index[0]]
        init_best = self.location[init_best]

        # 存储每个iteration的结果,画出收敛图
        self.iter_x = [0]
        self.iter_y = [1. / scores[sort_index[0]]]

    def random_init(self, num_total, num_city):
        tmp = [x for x in range(num_city)]
        result = []
        for i in range(num_total):
            random.shuffle(tmp)
            result.append(tmp.copy())
        return result

    def greedy_init(self, dis_mat, num_total, num_city):
        start_index = 0
        result = []
        for i in range(num_total):
            rest = [x for x in range(0, num_city)]
            # 所有起始点都已经生成了
            if start_index >= num_city:
                start_index = np.random.randint(0, num_city)
                result.append(result[start_index].copy())
                continue
            current = start_index
            rest.remove(current)
            # 找到一条最近邻路径
            result_one = [current]
            while len(rest) != 0:
                tmp_min = math.inf
                tmp_choose = -1
                for x in rest:
                    if dis_mat[current][x] < tmp_min:
                        tmp_min = dis_mat[current][x]
                        tmp_choose = x

                current = tmp_choose
                result_one.append(tmp_choose)
                rest.remove(tmp_choose)
            result.append(result_one)
            start_index += 1
        return result
    # 计算不同城市之间的距离
    def compute_dis_mat(self, num_city, location):
        dis_mat = np.zeros((num_city, num_city))
        for i in range(num_city):
            for j in range(num_city):
                if i == j:
                    dis_mat[i][j] = np.inf
                    continue
                a = location[i]
                b = location[j]
                tmp = np.sqrt(sum([(x[0] - x[1]) ** 2 for x in zip(a, b)]))
                dis_mat[i][j] = tmp
        return dis_mat

    # 计算路径长度
    def compute_pathlen(self, path, dis_mat):
        try:
            a = path[0]
            b = path[-1]
        except:
            import pdb
            pdb.set_trace()
        result = dis_mat[a][b]
        for i in range(len(path) - 1):
            a = path[i]
            b = path[i + 1]
            result += dis_mat[a][b]
        return result

    # 计算种群适应度
    def compute_adp(self, fruits):
        adp = []
        for fruit in fruits:
            if isinstance(fruit, int):
                import pdb
                pdb.set_trace()
            length = self.compute_pathlen(fruit, self.dis_mat)
            adp.append(1.0 / length)
        return np.array(adp)

    def swap_part(self, list1, list2):
        index = len(list1)
        list = list1 + list2
        list = list[::-1]
        return list[:index], list[index:]

    def ga_cross(self, x, y):
        len_ = len(x)
        assert len(x) == len(y)
        path_list = [t for t in range(len_)]
        order = list(random.sample(path_list, 2))
        order.sort()
        start, end = order

        # 找到冲突点并存下他们的下标,x中存储的是y中的下标,y中存储x与它冲突的下标
        tmp = x[start:end]
        x_conflict_index = []
        for sub in tmp:
            index = y.index(sub)
            if not (index >= start and index < end):
                x_conflict_index.append(index)

        y_confict_index = []
        tmp = y[start:end]
        for sub in tmp:
            index = x.index(sub)
            if not (index >= start and index < end):
                y_confict_index.append(index)

        assert len(x_conflict_index) == len(y_confict_index)

        # 交叉
        tmp = x[start:end].copy()
        x[start:end] = y[start:end]
        y[start:end] = tmp

        # 解决冲突
        for index in range(len(x_conflict_index)):
            i = x_conflict_index[index]
            j = y_confict_index[index]
            y[i], x[j] = x[j], y[i]

        assert len(set(x)) == len_ and len(set(y)) == len_
        return list(x), list(y)

    def ga_parent(self, scores, ga_choose_ratio):
        sort_index = np.argsort(-scores).copy()
        sort_index = sort_index[0:int(ga_choose_ratio * len(sort_index))]
        parents = []
        parents_score = []
        for index in sort_index:
            parents.append(self.fruits[index])
            parents_score.append(scores[index])
        return parents, parents_score

    def ga_choose(self, genes_score, genes_choose):
        sum_score = sum(genes_score)
        score_ratio = [sub * 1.0 / sum_score for sub in genes_score]
        rand1 = np.random.rand()
        rand2 = np.random.rand()
        for i, sub in enumerate(score_ratio):
            if rand1 >= 0:
                rand1 -= sub
                if rand1 < 0:
                    index1 = i
            if rand2 >= 0:
                rand2 -= sub
                if rand2 < 0:
                    index2 = i
            if rand1 < 0 and rand2 < 0:
                break
        return list(genes_choose[index1]), list(genes_choose[index2])

    def ga_mutate(self, gene):
        path_list = [t for t in range(len(gene))]
        order = list(random.sample(path_list, 2))
        start, end = min(order), max(order)
        tmp = gene[start:end]
        # np.random.shuffle(tmp)
        tmp = tmp[::-1]
        gene[start:end] = tmp
        return list(gene)

    def ga(self):
        # 获得优质父代
        scores = self.compute_adp(self.fruits)
        # 选择部分优秀个体作为父代候选集合
        parents, parents_score = self.ga_parent(scores, self.ga_choose_ratio)
        tmp_best_one = parents[0]
        tmp_best_score = parents_score[0]
        # 新的种群fruits
        fruits = parents.copy()
        # 生成新的种群
        while len(fruits) < self.num_total:
            # 轮盘赌方式对父代进行选择
            gene_x, gene_y = self.ga_choose(parents_score, parents)
            # 交叉
            gene_x_new, gene_y_new = self.ga_cross(gene_x, gene_y)
            # 变异
            if np.random.rand() < self.mutate_ratio:
                gene_x_new = self.ga_mutate(gene_x_new)
            if np.random.rand() < self.mutate_ratio:
                gene_y_new = self.ga_mutate(gene_y_new)
            x_adp = 1. / self.compute_pathlen(gene_x_new, self.dis_mat)
            y_adp = 1. / self.compute_pathlen(gene_y_new, self.dis_mat)
            # 将适应度高的放入种群中
            if x_adp > y_adp and (not gene_x_new in fruits):
                fruits.append(gene_x_new)
            elif x_adp <= y_adp and (not gene_y_new in fruits):
                fruits.append(gene_y_new)

        self.fruits = fruits

        return tmp_best_one, tmp_best_score

    def run(self):
        BEST_LIST = None
        best_score = -math.inf
        self.best_record = []
        for i in range(1, self.iteration + 1):
            tmp_best_one, tmp_best_score = self.ga()
            self.iter_x.append(i)
            self.iter_y.append(1. / tmp_best_score)
            if tmp_best_score > best_score:
                best_score = tmp_best_score
                BEST_LIST = tmp_best_one
            self.best_record.append(1./best_score)
            print(i,1./best_score)
        print(1./best_score)
        return self.location[BEST_LIST], 1. / best_score


# 读取数据
def read_tsp(path):
    lines = open(path, 'r').readlines()
    assert 'NODE_COORD_SECTION\n' in lines
    index = lines.index('NODE_COORD_SECTION\n')
    data = lines[index + 1:-1]
    tmp = []
    for line in data:
        line = line.strip().split(' ')
        if line[0] == 'EOF':
            continue
        tmpline = []
        for x in line:
            if x == '':
                continue
            else:
                tmpline.append(float(x))
        if tmpline == []:
            continue
        tmp.append(tmpline)
    data = tmp
    return data


data = read_tsp('data/st70.tsp')

data = np.array(data)
data = data[:, 1:]
Best, Best_path = math.inf, None

model = GA(num_city=data.shape[0], num_total=25, iteration=500, data=data.copy())
path, path_len = model.run()
if path_len < Best:
    Best = path_len
    Best_path = path
# 加上一行因为会回到起点
fig, axs = plt.subplots(2, 1, sharex=False, sharey=False)
axs[0].scatter(Best_path[:, 0], Best_path[:,1])
Best_path = np.vstack([Best_path, Best_path[0]])
axs[0].plot(Best_path[:, 0], Best_path[:, 1])
axs[0].set_title('规划结果')
iterations = range(model.iteration)
best_record = model.best_record
axs[1].plot(iterations, best_record)
axs[1].set_title('收敛曲线')
plt.show()

这里需要导入数据集
st70.tsp

NAME: st70
TYPE: TSP
COMMENT: 70-city problem (Smith/Thompson)
DIMENSION: 70
EDGE_WEIGHT_TYPE : EUC_2D
NODE_COORD_SECTION
1 64 96
2 80 39
3 69 23
4 72 42
5 48 67
6 58 43
7 81 34
8 79 17
9 30 23
10 42 67
11 7 76
12 29 51
13 78 92
14 64 8
15 95 57
16 57 91
17 40 35
18 68 40
19 92 34
20 62 1
21 28 43
22 76 73
23 67 88
24 93 54
25 6 8
26 87 18
27 30 9
28 77 13
29 78 94
30 55 3
31 82 88
32 73 28
33 20 55
34 27 43
35 95 86
36 67 99
37 48 83
38 75 81
39 8 19
40 20 18
41 54 38
42 63 36
43 44 33
44 52 18
45 12 13
46 25 5
47 58 85
48 5 67
49 90 9
50 41 76
51 25 76
52 37 64
53 56 63
54 10 55
55 98 7
56 16 74
57 89 60
58 48 82
59 81 76
60 29 60
61 17 22
62 5 45
63 79 70
64 9 100
65 17 82
66 74 67
67 10 68
68 48 19
69 83 86
70 84 94
EOF

运行截图

在这里插入图片描述
在这里插入图片描述

使用遗传算法解决旅行家问题

基本代码和数据集


在这里插入图片描述

# -*- encoding: utf-8 -*-
import numpy as np
import pandas as pd
from Draw import *


class TSP(object):
    citys = np.array([])  # 城市数组
    citys_name = np.array([])  #城市名字数组
    pop_size = 50  # 种群大小
    c_rate = 0.7  # 交叉率
    m_rate = 0.05  # 突变率
    pop = np.array([])  # 种群数组
    fitness = np.array([])  # 适应度数组(距离)
    city_size = -1  # 标记城市数目
    ga_num = 200  # 最大迭代次数
    best_dist = -1  # 记录目前最优距离
    best_gen = []  # 记录目前最优旅行方案
    dw = Draw()  # 绘图类



    #初始化数据
    def __init__(self, c_rate, m_rate, pop_size, ga_num):
        self.fitness = np.zeros(self.pop_size)
        self.c_rate = c_rate
        self.m_rate = m_rate
        self.pop_size = pop_size
        self.ga_num = ga_num

    def init(self):
        tsp = self
        tsp.load_Citys2()  # 加载城市数据,调用City2
        tsp.pop = tsp.creat_pop(tsp.pop_size)  # 创建种群
        tsp.fitness = tsp.get_fitness(tsp.pop)  # 计算初始种群适应度
        tsp.dw.bound_x = [np.min(tsp.citys[:, 0]), np.max(tsp.citys[:, 0])]  # 计算绘图时的X界,min,max
        tsp.dw.bound_y = [np.min(tsp.citys[:, 1]), np.max(tsp.citys[:, 1])]  # 计算绘图时的Y界
        tsp.dw.set_xybound(tsp.dw.bound_x, tsp.dw.bound_y)  # 设置边界

    def creat_pop(self, size):
        pop = []
        for i in range(size):
            gene = np.arange(self.citys.shape[0])  # 问题的解,基因,种群中的个体:[0,...,city_size]
            np.random.shuffle(gene)  # 打乱数组[0,...,city_size]
            pop.append(gene)   # 加入种群
        #array数组
        return np.array(pop)

    def get_fitness(self, pop):
        d = np.array([])  # 适应度记录数组
        for i in range(pop.shape[0]):#行
            gen = pop[i]  # 取其中一条基因(编码解,个体)
            dis = self.gen_distance(gen)  # 计算此基因优劣(距离长短)
            dis = self.best_dist / dis  # 当前最优距离除以当前pop[i](个体)距离;越近适应度越高,最优适应度为1
            d = np.append(d, dis)  # 保存适应度pop[i]     d=d.append(dis)
        return d

    def get_local_fitness(self, gen, i):
        '''
        计算地i个城市的邻域
        交换基因数组中任意两个值组成的解集:称为邻域。计算领域内所有可能的适应度
        :param gen:城市路径
        :param i:第i城市
        :return:第i城市的局部适应度
        '''
        di = 0
        fi = 0
        if i == 0:
            di = self.ct_distance(self.citys[gen[0]], self.citys[gen[-1]])
        else:
            di = self.ct_distance(self.citys[gen[i]], self.citys[gen[i - 1]])
        od = []
        for j in range(self.city_size):
            if i != j:
                #交换基因数组中任意两个值组成的解集:称为邻域。计算领域内所有可能的适应度
                od.append(self.ct_distance(self.citys[gen[i]], self.citys[gen[i - 1]]))
        mind = np.min(od)
        fi = di - mind
        return fi

    def EO(self, gen):
        # 极值优化,传统遗传算法性能不好,这里混合EO
        # 其会在整个基因的领域内,寻找一个最佳变换以更新基因
        local_fitness = []
        for g in range(self.city_size):
            f = self.get_local_fitness(gen, g)
            local_fitness.append(f)
        max_city_i = np.argmax(local_fitness)
        maxgen = np.copy(gen)
        if 1 < max_city_i < self.city_size - 1:
            for j in range(max_city_i):
                maxgen = np.copy(gen)
                jj = max_city_i
                while jj < self.city_size:
                    gen1 = self.exechange_gen(maxgen, j, jj)
                    d = self.gen_distance(maxgen)
                    d1 = self.gen_distance(gen1)
                    if d > d1:
                        maxgen = gen1[:]
                    jj += 1
        gen = maxgen
        return gen
    def exechange_gen(self, gen, i, j):
        # 函数:交换基因中i,j值
        c = gen[j]
        gen[j] = gen[i]
        gen[i] = c
        return gen

    def select_pop(self, pop):
        # 选择种群,优胜劣汰,策略1:低于平均的要替换改变
        best_f_index = np.argmax(self.fitness)
        #av表示平均数
        av = np.median(self.fitness, axis=0)
        for i in range(self.pop_size):
            if i != best_f_index and self.fitness[i] < av:
                pi = self.cross(pop[best_f_index], pop[i])
                pi = self.mutate(pi)
                pop[i, :] = pi[:]
        return pop

    def select_pop2(self, pop):
        # 选择种群,优胜劣汰,策略2:轮盘赌,适应度低的替换的概率大
        probility = self.fitness / self.fitness.sum()
        idx = np.random.choice(np.arange(self.pop_size), size=self.pop_size, replace=True, p=probility)
        n_pop = pop[idx, :]
        return n_pop

    def cross(self, parent1, parent2):
        """交叉p1,p2的部分基因片段"""
        #交叉率大于设定的,退出,返回parent1
        if np.random.rand() > self.c_rate:
            return parent1
        #在index1与index2进行交叉基因片段
        index1 = np.random.randint(0, self.city_size - 1)
        index2 = np.random.randint(index1, self.city_size - 1)
        tempGene = parent2[index1:index2]  # 交叉的基因片段,例如:[20,24]
        #newGene用来储存
        newGene = []
        p1len = 0
        #对parent1的数据进行遍历
        for g in parent1:
            #若等于索引值,直接加上交叉的基因片段
            if p1len == index1:
                newGene.extend(tempGene)  # 插入基因片段
            #如果g不在交叉的基因片段,也加上,避免重复。
            if g not in tempGene:
                newGene.append(g)
            p1len += 1
        newGene = np.array(newGene)

        #检查一下是不是城市的数量
        if newGene.shape[0] != self.city_size:
            print('c error')
            return self.creat_pop(1)
            # return parent1
        return newGene

    def mutate(self, gene):
        """突变"""
        if np.random.rand() > self.m_rate:
            return gene
        #随机生成两个索引节点,
        #np.random.randint返回一个随机整型数,范围从低(包括)到高(不包括),即[low, high)。
        index1 = np.random.randint(0, self.city_size - 1)
        index2 = np.random.randint(index1, self.city_size - 1)
        newGene = self.reverse_gen(gene, index1, index2)
        if newGene.shape[0] != self.city_size:
            print('m error')
            return self.creat_pop(1)
        return newGene

    def reverse_gen(self, gen, i, j):
        # 函数:翻转基因中i到j之间的基因片段
        #i>=j,j=33,生成的index1,index2发生错误。
        if i >= j:
            return gen
        if j > self.city_size - 1:
            return gen
        #先做一个备份parent1
        parent1 = np.copy(gen)
        #tempGene为parent1的i-j
        tempGene = parent1[i:j]
        newGene = []
        p1len = 0
        #对parent1进行遍历,
        for g in parent1:
            if p1len == i:
                newGene.extend(tempGene[::-1])  # 插入基因片段(步长为-1,倒着插入)
            if g not in tempGene:
                newGene.append(g) #如果g不在tempGene,追加上
            p1len += 1
        return np.array(newGene)


    def evolution(self):
        # 主程序:迭代进化种群
        tsp = self
        #ga_num 最大迭代次数
        x_data = []
        y_data = []

        for i in range(self.ga_num):
            #最好的索引,argmax返回的是最大数的索引
            best_f_index = np.argmax(tsp.fitness)
            worst_f_index = np.argmin(tsp.fitness)

            #本地最好的路线,将种群(最好的索引),local_best_gen是个1*34
            local_best_gen = tsp.pop[best_f_index]
            #最优的距离
            local_best_dist = tsp.gen_distance(local_best_gen)
            if i == 0:
                #第一个,初始化,以下两个存着最好的
                tsp.best_gen = local_best_gen
                tsp.best_dist = tsp.gen_distance(local_best_gen)

            #出现更优秀的路程
            if local_best_dist < tsp.best_dist:
                tsp.best_dist = local_best_dist # 记录最优值(距离值)
                tsp.best_gen = local_best_gen  # 记录最个体基因(1*34)的基因,一个路线
                # 绘图
                tsp.dw.ax.cla()
                tsp.re_draw()
                #相当于sleep(0.001)
                tsp.dw.plt.pause(0.001)
            else:
                tsp.pop[worst_f_index] = self.best_gen

            #打印出基因代数和距离
            print('gen:%d evo,best dist :%s' % (i, self.best_dist))


            x_data.append(i)
            y_data.append(self.best_dist)

            # 设置数据图的标题


            tsp.pop = tsp.select_pop(tsp.pop)  # 选择淘汰种群
            tsp.fitness = tsp.get_fitness(tsp.pop)  # 计算种群适应度
            for j in range(self.pop_size):
                r = np.random.randint(0, self.pop_size - 1)
                if j != r:
                    tsp.pop[j] = tsp.cross(tsp.pop[j], tsp.pop[r])  # 交叉种群中第j,r个体的基因
                    tsp.pop[j] = tsp.mutate(tsp.pop[j])  # 突变种群中第j个体的基因
            tsp.best_dist = tsp.gen_distance(self.best_gen)  # 记录最优值

        plt.title('TSP问题:34城市旅游')
        # 第一个列表代表横坐标的值,第二个代表纵坐标的值
        plt.plot(x_data, y_data)
        # 设置两条坐标轴的标签
        plt.xlabel("经度")
        plt.ylabel("纬度")
        # print(x_data)
        # print(y_data)


    def load_Citys2(self, file='china.csv', delm=';'):
        # 中国34城市经纬度
        #分delimiter隔符。header头,从哪里开始读
        data = pd.read_csv(file, delimiter=delm, header=None).values
        #所有行,第1-2列
        self.citys = data[:, 1:]
        #第0列,所有行
        self.citys_name = data[:, 0]
        #城市数量shape[0]为行数;shape[0]为列数
        self.city_size = data.shape[0]

    def gen_distance(self, gen):
        # 计算基因所代表的总旅行距离
        #传入的数据为种群数
        distance = 0.0
        for i in range(-1, len(self.citys) - 1):
            index1, index2 = gen[i], gen[i + 1]
            city1, city2 = self.citys[index1], self.citys[index2]
            #距离公式
            distance += np.sqrt((city1[0] - city2[0]) ** 2 + (city1[1] - city2[1]) ** 2)
        return distance

    def ct_distance(self, city1, city2):
        # 计算2城市之间的距离
        d = np.sqrt((city1[0] - city2[0]) ** 2 + (city1[1] - city2[1]) ** 2)
        return d

    def draw_citys_way(self, gen):
        '''
        根据一条基因gen绘制一条旅行路线
        :param gen:
        :return:
        '''
        tsp = self
        dw = self.dw
        m = gen.shape[0]#多少行
        tsp.dw.set_xybound(tsp.dw.bound_x, tsp.dw.bound_y)
        for i in range(m):
            if i < m - 1:
                #获得基因地点的代数值
                best_i = tsp.best_gen[i]
                next_best_i = tsp.best_gen[i + 1]
                #城市
                best_icity = tsp.citys[best_i]
                next_best_icity = tsp.citys[next_best_i]

                dw.draw_line(best_icity, next_best_icity)
        #首位相连
        start = tsp.citys[tsp.best_gen[0]]
        end = tsp.citys[tsp.best_gen[-1]]
        dw.draw_line(end, start)

    def draw_citys_name(self, gen, size=5):
        '''
        根据一条基因gen(路线)绘制对应城市名称
        '''
        tsp = self
        m = gen.shape[0]
        tsp.dw.set_xybound(tsp.dw.bound_x, tsp.dw.bound_y)
        for i in range(m):
            c = gen[i]
            best_icity = tsp.citys[c]
            tsp.dw.draw_text(best_icity[0], best_icity[1], tsp.citys_name[c], 10)

    def re_draw(self):
        # 重绘图;每次迭代后绘制一次,动态展示。
        tsp = self
        tsp.dw.draw_points(tsp.citys[:, 0], tsp.citys[:, 1])
        tsp.draw_citys_name(tsp.pop[0], 8)
        tsp.draw_citys_way(self.best_gen)


def main():
    #
    tsp = TSP(0.5, 0.1, 100, 500)
    tsp.init()
    tsp.evolution()
    tsp.re_draw()
    tsp.dw.plt.show()


if __name__ == '__main__':
    main()

在这里插入图片描述

import matplotlib.pyplot as plt
from matplotlib.lines import Line2D
import matplotlib.animation as animation

class Draw(object):
    #边界值
    bound_x = []
    bound_y = []

    def __init__(self):
        self.fig, self.ax = plt.subplots()
        self.plt = plt
        self.set_font()

    def draw_line(self, p_from, p_to):
        #画线函数
        #储存两个点的坐标
        line1 = [(p_from[0], p_from[1]), (p_to[0], p_to[1])]
        #zip匹配
        (line1_xs, line1_ys) = zip(*line1)
        self.ax.add_line(Line2D(line1_xs, line1_ys, linewidth=1, color='blue'))

    def draw_points(self, pointx, pointy):
        #画点
        self.ax.plot(pointx, pointy, 'ro')

    #设置边界
    def set_xybound(self, x_bd, y_bd):
        self.ax.axis([x_bd[0], x_bd[1], y_bd[0], y_bd[1]])

    def draw_text(self, x, y, text, size=8):
        #写入文本
        self.ax.text(x, y, text, fontsize=size)

    def set_font(self, ft_style='SimHei'):
        plt.rcParams['font.sans-serif'] = [ft_style]  #用来正常显示中文标签

    

在这里插入图片描述

import matplotlib.pyplot as plt  # 调用matplotlib中的子模块pyplot绘制折线图

# 解决中文显示问题
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

# 定义2个列表分别作为X轴、Y轴数据
x_data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
          30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
          57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83,
          84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108,
          109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130,
          131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152,
          153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174,
          175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196,
          197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218,
          219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240,
          241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262,
          263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284,
          285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306,
          307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328,
          329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350,
          351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372,
          373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 394,
          395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416,
          417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, 437, 438,
          439, 440, 441, 442, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, 460,
          461, 462, 463, 464, 465, 466, 467, 468, 469, 470, 471, 472, 473, 474, 475, 476, 477, 478, 479, 480, 481, 482,
          483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499]
y_data = [564.3572005522793, 525.8139896243653, 428.1402039165018, 395.73743500834706, 394.06860429583867,
          373.684464645136, 365.60282673151573, 345.53960499838325, 331.2057904610075, 318.760364597339,
          303.162734978924, 301.42654142792907, 324.64583395454457, 301.42654142792907, 286.65204026600344,
          286.65204026600344, 282.273279917727, 282.273279917727, 280.1240489659227, 280.1240489659227,
          263.21414723204833, 254.22777921677803, 254.22777921677803, 250.71667881027474, 250.71667881027474,
          250.50756156870992, 246.24627654938107, 243.8041742198946, 240.15416946358778, 233.2661303383399,
          233.2661303383399, 239.59565159058116, 245.4156684272969, 228.28636969404505, 223.25718187742706,
          234.39093411202532, 228.28636969404505, 228.28636969404505, 228.28636969404505, 228.28636969404505,
          223.25718187742706, 223.25718187742706, 223.25718187742706, 223.25718187742706, 223.25718187742706,
          223.25718187742706, 237.62255381361274, 218.7219498855295, 218.7219498855295, 218.7219498855295,
          218.7219498855295, 213.88717907524358, 213.88717907524358, 213.88717907524358, 213.88717907524358,
          213.88717907524358, 213.88717907524358, 210.38478374497757, 209.33239248439264, 209.33239248439264,
          206.78401520265885, 204.6494179326049, 202.52449291907507, 202.52449291907507, 209.40591607095607,
          202.52449291907507, 202.52449291907507, 196.47995538838418, 196.47995538838418, 190.37500614252744,
          190.37500614252744, 189.59159577864688, 189.59159577864688, 208.0505225509335, 188.16445411312182,
          188.16445411312182, 183.3306118846393, 183.3306118846393, 183.3306118846393, 180.91006531329387,
          180.91006531329387, 180.91006531329387, 180.91006531329387, 180.1372614132791, 180.1372614132791,
          173.88941629266455, 173.88941629266455, 176.59810679235267, 170.69606582130436, 170.69606582130436,
          170.69606582130436, 170.69606582130436, 170.69606582130436, 168.07668182016852, 168.07668182016852,
          168.07668182016852, 168.07668182016852, 168.07668182016852, 168.07668182016852, 168.07668182016852,
          168.07668182016852, 167.8576491945162, 167.8576491945162, 167.8576491945162, 167.8576491945162,
          167.8576491945162, 167.8576491945162, 167.8576491945162, 167.8576491945162, 167.8576491945162,
          167.8576491945162, 167.8576491945162, 167.8576491945162, 167.8576491945162, 177.3790464315465,
          167.8576491945162, 167.8576491945162, 167.8576491945162, 167.8576491945162, 167.8576491945162,
          167.8576491945162, 167.8576491945162, 167.8576491945162, 167.61076548111026, 167.61076548111026,
          164.97138190423385, 164.97138190423385, 164.97138190423385, 164.97138190423385, 164.97138190423385,
          164.72449819082792, 164.54586334812686, 164.54586334812686, 199.208730578168, 164.54586334812686,
          164.54586334812686, 164.54586334812686, 164.54586334812686, 164.29897963472092, 164.29897963472092,
          164.29897963472092, 164.29897963472092, 164.29897963472092, 164.29897963472092, 164.29897963472092,
          164.29897963472092, 164.29897963472092, 185.88553720859375, 164.29897963472092, 164.29897963472092,
          164.29897963472092, 164.29897963472092, 164.29897963472092, 164.29897963472092, 164.29897963472092,
          164.29897963472092, 164.29897963472092, 164.29897963472092, 164.29897963472092, 164.29897963472092,
          164.29897963472092, 164.29897963472092, 164.29897963472092, 162.57964890814006, 164.29897963472092,
          162.57964890814006, 158.7673551900737, 158.7673551900737, 158.7673551900737, 158.7673551900737,
          158.7673551900737, 158.7673551900737, 158.7673551900737, 158.7673551900737, 158.7673551900737,
          158.7673551900737, 158.7673551900737, 158.7673551900737, 158.1419649942265, 158.1419649942265,
          158.1419649942265, 158.1419649942265, 158.1419649942265, 165.4458885670924, 158.1419649942265,
          158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
          158.1419649942265, 158.1419649942265, 191.02831038858773, 158.1419649942265, 158.1419649942265,
          158.1419649942265, 158.1419649942265, 171.65859112307524, 158.1419649942265, 158.1419649942265,
          158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
          158.1419649942265, 164.0340772847696, 158.1419649942265, 158.1419649942265, 158.1419649942265,
          158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
          158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
          158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
          158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
          158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
          158.1419649942265, 158.1419649942265, 158.1419649942265, 179.9211681457678, 179.9211681457678,
          158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
          158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
          158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
          158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
          163.66825012378013, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
          158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
          158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
          158.1419649942265, 158.1419649942265, 171.91025362935008, 158.1419649942265, 158.1419649942265,
          209.80381193148267, 191.60574674226325, 158.1419649942265, 158.1419649942265, 158.1419649942265,
          158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
          158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
          158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
          158.1419649942265, 158.1419649942265, 175.8142105909829, 158.1419649942265, 158.1419649942265,
          158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
          158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
          158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
          167.026358254871, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
          158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
          158.1419649942265, 158.1419649942265, 158.1419649942265, 176.6464998788, 158.1419649942265, 158.1419649942265,
          158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
          158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
          158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
          158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
          158.1419649942265, 167.23953199487363, 158.1419649942265, 158.1419649942265, 158.1419649942265,
          158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
          158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
          158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
          158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
          158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 192.04319689552514,
          158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
          158.1419649942265, 158.1419649942265, 158.1419649942265, 163.16329458342935, 158.1419649942265,
          158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
          158.1419649942265, 158.1419649942265, 200.09613901232325, 158.1419649942265, 158.1419649942265,
          158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
          158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
          158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
          158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
          158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
          158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
          158.1419649942265, 161.73403495002682, 158.1419649942265, 158.1419649942265, 158.1419649942265,
          158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
          158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
          158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
          158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 170.9199683340315,
          158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
          194.74385775914007, 176.00797889997622, 158.1419649942265, 158.1419649942265, 158.1419649942265,
          158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
          158.1419649942265, 158.1419649942265, 161.17029153503222, 158.1419649942265, 158.1419649942265,
          158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
          158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
          158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265, 158.1419649942265,
          158.1419649942265, 158.1419649942265, 158.1419649942265, 200.08345964477837]

# 设置数据图的标题
plt.title('迭代代数与距离的关系')

# 第一个列表代表横坐标的值,第二个代表纵坐标的值
plt.plot(x_data, y_data)
# 设置两条坐标轴的标签
plt.xlabel("迭代代数")
plt.ylabel("距离/KM")

# 调用show()函数显示图形
plt.show()

在这里插入图片描述

北京 ;116.46;39.92
天津 ;117.2;39.13
上海 ;121.48;31.22
重庆 ;106.54;29.59
拉萨 ;91.11;29.97
乌鲁木齐 ;87.68;43.77
银川 ;106.27;38.47
呼和浩特 ;111.65;40.82
南宁  ;108.33;22.84
哈尔滨  ;126.63;45.75
长春  ;125.35;43.88
沈阳  ;123.38;41.8
石家庄  ;114.48;38.03
太原  ;112.53;37.87
西宁 ;101.74;36.56
济南 ;117;36.65
郑州 ;113.6;34.76
南京;118.78;32.04
合肥;117.27;31.86
杭州;120.19;30.26
福州;119.3;26.08
南昌;115.89;28.68
长沙;113;28.21
武汉;114.31;30.52
广州;113.23;23.16
台北;121.5;25.05
海口;110.35;20.02
兰州;103.73;36.03
西安;108.95;34.27
成都;104.06;30.67
贵阳;106.71;26.57
昆明;102.73;25.04
香港;114.1;22.2
澳门;113.33;22.13

运行截图

在这里插入图片描述

运行视频展示

视频展示
b站视频链接

小结

在这里插入图片描述

  • 4
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

汪程序猿

就当请我吃顿饭

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值