├── input_arr.npy ├── output_arr.npy ├── test_input_arr.npy ├── test_output_arr.npy ├── 7.generate-test-data.py ├── 10.calculate-average-error.py ├── 3.merge-two-sheets.py ├── 2.division area.py ├── 4.area-dicision-with-poi.py ├── 5.demands-statistics.py ├── 1.geohash-decode.py ├── 6.generate-final-sheet.py ├── 8.save-test & train-data.py ├── 9.BP Neural Networks.py └── 11.Ant Colony Algorithm.py /input_arr.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lujiaxuan0520/Prediction-and-Scheduling-of-Shared-Bike/HEAD/input_arr.npy -------------------------------------------------------------------------------- /output_arr.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lujiaxuan0520/Prediction-and-Scheduling-of-Shared-Bike/HEAD/output_arr.npy -------------------------------------------------------------------------------- /test_input_arr.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lujiaxuan0520/Prediction-and-Scheduling-of-Shared-Bike/HEAD/test_input_arr.npy -------------------------------------------------------------------------------- /test_output_arr.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lujiaxuan0520/Prediction-and-Scheduling-of-Shared-Bike/HEAD/test_output_arr.npy -------------------------------------------------------------------------------- /7.generate-test-data.py: -------------------------------------------------------------------------------- 1 | #coding=utf-8 2 | import csv 3 | import random 4 | 5 | filename = '训练集2.csv' 6 | with open(filename) as f: 7 | reader = csv.reader(f) 8 | data = list(reader) 9 | 10 | new_data=[] 11 | for i in range(4000): 12 | rand=random.randint(0,40963) 13 | new_data.append(data[rand]) 14 | 15 | with open('测试集.csv', 'w', newline='') as f: 16 | writer = csv.writer(f) 17 | count = 0 18 | for row in new_data: 19 | writer.writerow(row) 20 | count += 1 21 | print(count) -------------------------------------------------------------------------------- /10.calculate-average-error.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | import math 3 | import numpy as np 4 | 5 | # 计算平均误差 6 | predict_result = np.loadtxt("predict_result.txt") 7 | predict_result.reshape(4000, 1) 8 | test_output_arr=np.load("test_output_arr.npy") 9 | ntest_output_arr=[] 10 | for i in range(len(test_output_arr)): 11 | ntest_output_arr.append(test_output_arr[i][0]) 12 | ntest_output_arr = np.array(ntest_output_arr) 13 | avg_error = (np.abs(predict_result - ntest_output_arr)) / ntest_output_arr 14 | avg_error = np.mean(avg_error) 15 | print('平均误差:', str(avg_error)) 16 | -------------------------------------------------------------------------------- /3.merge-two-sheets.py: -------------------------------------------------------------------------------- 1 | #coding=utf-8 2 | import xlrd 3 | import csv 4 | data = xlrd.open_workbook('北京poi数据订单1.xlsx') 5 | table = data.sheets()[0] 6 | nrows = table.nrows 7 | new_data=[] 8 | for i in range(1,nrows): 9 | new_data.append(table.row_values(i)) 10 | data = xlrd.open_workbook('北京poi数据订单2.xlsx') 11 | table = data.sheets()[0] 12 | nrows = table.nrows 13 | for i in range(1,nrows): 14 | new_data.append(table.row_values(i)) 15 | with open('北京poi数据汇总表.csv', 'w', newline='') as f: 16 | writer = csv.writer(f) 17 | count = 0 18 | for row in new_data: 19 | writer.writerow(row) 20 | count += 1 21 | print(count) -------------------------------------------------------------------------------- /2.division area.py: -------------------------------------------------------------------------------- 1 | import csv 2 | left_1 = (40.011039, 116.221884)#左上角 3 | left_2 = (39.779632, 116.530812)#右下角 4 | width = round(((left_1[0] - left_2[0])/200), 9) 5 | length = round(((left_2[1] - left_1[1])/200), 9) 6 | print(length, width) 7 | 8 | 9 | def mark(lat, lot): 10 | if lat > left_1[0] or lat < left_2[0] or lot < left_1[1] or lot > left_2[1]: 11 | return -1 12 | else: 13 | row = (lat - left_2[0])//width 14 | col = (lot - left_1[1])//length 15 | tag = row * 200 + col 16 | return int(tag) 17 | 18 | filename = 'example1.csv' 19 | 20 | 21 | with open(filename) as f: 22 | reader = csv.reader(f) 23 | data = list(reader) 24 | 25 | 26 | #已经得到data 27 | 28 | new_data = [] 29 | for word in data: 30 | new_line = word 31 | new_line.append(mark(float(word[2]), float(word[3]))) 32 | new_line.append(mark(float(word[4]), float(word[5]))) 33 | new_data.append(new_line) 34 | 35 | 36 | with open('example2.csv', 'w', newline='') as f: 37 | writer = csv.writer(f) 38 | count = 0 39 | for row in new_data: 40 | if row[-1] != -1 and row[-2] != -1: 41 | writer.writerow(row) 42 | count += 1 43 | print(count) 44 | 45 | -------------------------------------------------------------------------------- /4.area-dicision-with-poi.py: -------------------------------------------------------------------------------- 1 | #coding=utf-8 2 | import csv 3 | left_1 = (40.011039, 116.221884) 4 | left_2 = (39.779632, 116.530812) 5 | right_1 = (40.011039, 116.221884) 6 | right_2 = (39.779632, 116.530812) 7 | width = round(((left_1[0] - left_2[0])/200), 9) 8 | length = round(((left_2[1] - left_1[1])/200), 9) 9 | print(length, width) 10 | 11 | def mark(lat, lot): 12 | if lat > left_1[0] or lat < left_2[0] or lot < left_1[1] or lot > left_2[1]: 13 | return -1 14 | else: 15 | row = (lat - left_2[0])//width 16 | col = (lot - left_1[1])//length 17 | tag = row * 200 + col 18 | return int(tag) 19 | 20 | filename = '北京poi数据汇总表.csv' 21 | 22 | 23 | with open(filename) as f: 24 | reader = csv.reader(f) 25 | data = list(reader) 26 | 27 | 28 | #已经得到data 29 | 30 | new_data = [] 31 | for word in data: 32 | new_line = word 33 | new_line.append(mark(float(word[4]), float(word[3]))) 34 | new_data.append(new_line) 35 | 36 | 37 | with open('北京poi数据区域划分结果.csv', 'w', newline='') as f: 38 | writer = csv.writer(f) 39 | count = 0 40 | for row in new_data: 41 | if row[-1] != -1: 42 | writer.writerow(row) 43 | count += 1 44 | print(count) -------------------------------------------------------------------------------- /5.demands-statistics.py: -------------------------------------------------------------------------------- 1 | #coding=utf-8 2 | import csv 3 | import re 4 | import math 5 | 6 | filename = '单车数据区域划分结果.csv' 7 | with open(filename) as f: 8 | reader = csv.reader(f) 9 | data = list(reader) 10 | 11 | dic=dict() 12 | for line in data: 13 | time=line[1] 14 | time=int(re.split(r':',time)[0]) 15 | time=str(math.floor(time/2)) 16 | key=str(line[6])+'-'+time 17 | if key in dic.keys(): 18 | dic[key]+=1 19 | else: 20 | dic[key]=1 21 | 22 | with open('单车各区域与时间段需求量统计.csv', 'w', newline='') as f: 23 | writer = csv.writer(f) 24 | count = 0 25 | for items in dic.items(): 26 | new_line=[] 27 | key=items[0] 28 | value=items[1] 29 | split=re.split(r'-',key) 30 | district=int(split[0]) 31 | time=int(split[1]) 32 | new_line.append(district) 33 | new_line.append(time) 34 | new_line.append(value) 35 | writer.writerow(new_line) 36 | count += 1 37 | for i in range(40000): 38 | for j in range(12): 39 | s=str(i)+'-'+str(j) 40 | if s not in dic.keys(): 41 | count+=1 42 | new_line=[] 43 | new_line.append(i) 44 | new_line.append(j) 45 | new_line.append(0) 46 | writer.writerow(new_line) 47 | 48 | print(count) -------------------------------------------------------------------------------- /1.geohash-decode.py: -------------------------------------------------------------------------------- 1 | #coding=utf-8 2 | import random 3 | 4 | #geohash模块提取的 5 | __base32 = '0123456789bcdefghjkmnpqrstuvwxyz' 6 | __decodemap = { } 7 | for i in range(len(__base32)): 8 | __decodemap[__base32[i]] = i 9 | del i 10 | 11 | def decode_exactly(geohash): 12 | lat_interval, lon_interval = (-90.0, 90.0), (-180.0, 180.0) 13 | lat_err, lon_err = 90.0, 180.0 14 | is_even = True 15 | for c in geohash: 16 | cd = __decodemap[c] 17 | for mask in [16, 8, 4, 2, 1]: 18 | if is_even: # adds longitude info 19 | lon_err /= 2 20 | if cd & mask: 21 | lon_interval = ((lon_interval[0]+lon_interval[1])/2, lon_interval[1]) 22 | else: 23 | lon_interval = (lon_interval[0], (lon_interval[0]+lon_interval[1])/2) 24 | else: # adds latitude info 25 | lat_err /= 2 26 | if cd & mask: 27 | lat_interval = ((lat_interval[0]+lat_interval[1])/2, lat_interval[1]) 28 | else: 29 | lat_interval = (lat_interval[0], (lat_interval[0]+lat_interval[1])/2) 30 | is_even = not is_even 31 | lat = (lat_interval[0] + lat_interval[1]) / 2 32 | lon = (lon_interval[0] + lon_interval[1]) / 2 33 | return lat, lon, lat_err, lon_err 34 | 35 | def main(): 36 | with open('end.txt','r') as fp: 37 | data=fp.read().split() 38 | data_set=tuple(data) 39 | with open('_end_lat_lot.txt','a') as fw: 40 | for each in data_set: 41 | e=decode_exactly(each) 42 | _str=str(e[0])+','+str(e[1]) 43 | fw.write(_str) 44 | fw.write('\n') 45 | 46 | 47 | 48 | if __name__=='__main__': 49 | main() -------------------------------------------------------------------------------- /6.generate-final-sheet.py: -------------------------------------------------------------------------------- 1 | #coding=utf-8 2 | import csv 3 | import re 4 | import math 5 | 6 | def Index(category): 7 | s=category[:2] 8 | if s=="餐饮": 9 | return 0 10 | elif s=="道路" or s=="地名" or s=="通行": 11 | return 1 12 | elif s=="公共" or s=="生活" or s=="事件" or s=="体育" or s=="科教" or s=="医疗": 13 | return 2 14 | elif s=="公司" or s=="金融" or s=="政府": 15 | return 3 16 | elif s=="购物": 17 | return 4 18 | elif s=="交通": 19 | return 5 20 | elif s=="商务" or s=="住宿": 21 | return 6 22 | else: 23 | return -1 24 | 25 | filename = '北京poi数据区域划分结果.csv' 26 | with open(filename) as f: 27 | reader = csv.reader(f) 28 | data = list(reader) 29 | 30 | dic=dict() 31 | count=0 32 | for line in data: 33 | category=line[1] 34 | index=Index(category) 35 | district=int(line[20]) 36 | if index!=-1: 37 | if district not in dic.keys(): 38 | dic[district]=[0,0,0,0,0,0,0] 39 | count+=1 40 | else: 41 | dic[district][index]+=1 42 | for i in range(40000): 43 | if i not in dic.keys(): 44 | dic[i]=[0,0,0,0,0,0,0] 45 | count+=1 46 | 47 | 48 | with open("单车各区域与时间段需求量统计.csv") as f: 49 | reader1 = csv.reader(f) 50 | data1 = list(reader1) 51 | 52 | new_data = [] 53 | for word in data1: 54 | district=int(word[0]) 55 | new_line = word 56 | new_line.append(dic[district][0]) 57 | new_line.append(dic[district][1]) 58 | new_line.append(dic[district][2]) 59 | new_line.append(dic[district][3]) 60 | new_line.append(dic[district][4]) 61 | new_line.append(dic[district][5]) 62 | new_line.append(dic[district][6]) 63 | new_data.append(new_line) 64 | 65 | with open('各时间段各区域地理画像与需求量对照表.csv', 'w', newline='') as f: 66 | writer = csv.writer(f) 67 | count = 0 68 | for row in new_data: 69 | writer.writerow(row) 70 | count += 1 71 | print(count) -------------------------------------------------------------------------------- /8.save-test & train-data.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | #coding=utf-8 3 | import numpy as np 4 | import csv 5 | filename = '训练集2.csv' 6 | with open(filename) as f: 7 | reader = csv.reader(f) 8 | data = list(reader) 9 | #input_arr = np.array([None, None, None, None, None, None, None, None, None,None, None, None, None, None, None]) 10 | #output_arr = np.array([None]) 11 | input_arr=np.zeros((40963,23)) 12 | output_arr=np.zeros((40963,1)) 13 | for i in range(0, 40963): 14 | input_arr[i][0]=float(data[i][1]) 15 | input_arr[i][1]=float(data[i][2]) 16 | input_arr[i][2]=int(data[i][4]) 17 | input_arr[i][3] = int(data[i][5]) 18 | input_arr[i][4] = int(data[i][6]) 19 | input_arr[i][5] = int(data[i][7]) 20 | input_arr[i][6] = int(data[i][8]) 21 | input_arr[i][7] = int(data[i][9]) 22 | input_arr[i][8] = int(data[i][10]) 23 | input_arr[i][9] = int(data[i][11]) 24 | input_arr[i][10] = int(data[i][12]) 25 | input_arr[i][11] = int(data[i][13]) 26 | input_arr[i][12] = int(data[i][14]) 27 | input_arr[i][13] = int(data[i][15]) 28 | input_arr[i][14]=int(data[i][24]) 29 | input_arr[i][15] = int(data[i][17]) 30 | input_arr[i][16] = int(data[i][18]) 31 | input_arr[i][17] = int(data[i][19]) 32 | input_arr[i][18] = int(data[i][20]) 33 | input_arr[i][19] = int(data[i][21]) 34 | input_arr[i][20] = int(data[i][22]) 35 | input_arr[i][21] = int(data[i][23]) 36 | input_arr[i][22]=int(data[i][25]) 37 | output_arr[i][0]=int(data[i][16]) 38 | #row = np.array( 39 | #[lat,lon,t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,poiNum]) 40 | #input_arr = np.row_stack((input_arr, row)) 41 | #output_arr = np.row_stack((output_arr, [demand])) 42 | #input_arr = np.delete(input_arr, 0, 0) # 删除第一行 43 | #output_arr = np.delete(output_arr, 0, 0) 44 | np.save("input_arr.npy", input_arr) 45 | np.save("output_arr.npy", output_arr) 46 | 47 | filename = '测试集.csv' 48 | with open(filename) as f: 49 | reader = csv.reader(f) 50 | data = list(reader) 51 | #test_input_arr = np.array([None, None, None, None, None, None, None, None, None,None, None, None, None, None, None]) 52 | #test_output_arr = np.array([None]) 53 | test_input_arr=np.zeros((4000,23)) 54 | test_output_arr=np.zeros((4000,1)) 55 | for i in range(0, 4000): 56 | test_input_arr[i][0] = float(data[i][1]) 57 | test_input_arr[i][1] = float(data[i][2]) 58 | test_input_arr[i][2] = int(data[i][4]) 59 | test_input_arr[i][3] = int(data[i][5]) 60 | test_input_arr[i][4] = int(data[i][6]) 61 | test_input_arr[i][5] = int(data[i][7]) 62 | test_input_arr[i][6] = int(data[i][8]) 63 | test_input_arr[i][7] = int(data[i][9]) 64 | test_input_arr[i][8] = int(data[i][10]) 65 | test_input_arr[i][9] = int(data[i][11]) 66 | test_input_arr[i][10] = int(data[i][12]) 67 | test_input_arr[i][11] = int(data[i][13]) 68 | test_input_arr[i][12] = int(data[i][14]) 69 | test_input_arr[i][13] = int(data[i][15]) 70 | test_input_arr[i][14] = int(data[i][24]) 71 | test_input_arr[i][15] = int(data[i][17]) 72 | test_input_arr[i][16] = int(data[i][18]) 73 | test_input_arr[i][17] = int(data[i][19]) 74 | test_input_arr[i][18] = int(data[i][20]) 75 | test_input_arr[i][19] = int(data[i][21]) 76 | test_input_arr[i][20] = int(data[i][22]) 77 | test_input_arr[i][21] = int(data[i][23]) 78 | test_input_arr[i][22] = int(data[i][25]) 79 | test_output_arr[i][0] = int(data[i][16]) 80 | #row = np.array( 81 | #[lat, lon, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, poiNum]) 82 | #test_input_arr = np.row_stack((test_input_arr, row)) 83 | #test_output_arr = np.row_stack((test_output_arr, [demand])) 84 | #test_input_arr = np.delete(test_input_arr, 0, 0) # 删除第一行 85 | #test_output_arr = np.delete(test_output_arr, 0, 0) 86 | np.save("test_input_arr.npy", test_input_arr) 87 | np.save("test_output_arr.npy", test_output_arr) -------------------------------------------------------------------------------- /9.BP Neural Networks.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # coding=utf-8 3 | import tensorflow as tf 4 | import numpy as np 5 | from sklearn.preprocessing import scale 6 | import csv 7 | 8 | 9 | # neuron_size为输入神经元的列表,第一个元素为输入层元素的个数,最后一个为输出层元素 10 | class Bpnn: 11 | def __init__(self, neuron_size, learning_rate): 12 | self.input_holder = tf.placeholder(tf.float32, [None, neuron_size[0]]) 13 | self.output_holder = tf.placeholder(tf.float32, [None, neuron_size[-1]]) 14 | self.weight = {} 15 | self.bias = {} 16 | self.layers = {} 17 | for i in range(len(neuron_size) - 1): 18 | # 第i+1层神经元与前一层输入的各个权重w组成的矩阵 19 | self.weight[i+1] = tf.Variable(tf.random_normal([neuron_size[i], neuron_size[i+1]])) 20 | for i in range(len(neuron_size) - 1): 21 | # 第i+1层每个神经元的偏移量b 22 | self.bias[i+1] = tf.Variable(tf.random_normal([neuron_size[i+1]])) 23 | # layers存放第i层wx+b作用relu激活函数后的结果 24 | self.layers[1] = tf.nn.tanh(tf.add(tf.matmul(self.input_holder, self.weight[1]), self.bias[1])) 25 | layer_stack = [self.layers[1]] 26 | for i in range(len(neuron_size) - 1): 27 | if i != 0 and i != 1: 28 | # 计算中间层的layers:r(wx+b) 29 | self.layers[i] = tf.nn.relu(tf.add(tf.matmul(layer_stack[-1], self.weight[i]), self.bias[i])) 30 | layer_stack.append(self.layers[i]) 31 | # outlayer为预测的输出值 32 | self.out_layer = tf.add(tf.matmul(layer_stack[-1], self.weight[len(neuron_size) - 1]), self.bias[len(neuron_size) - 1]) 33 | # 损失函数:计算输出的目标值与预测值的偏差 34 | self.loss = tf.reduce_mean(tf.reduce_sum(tf.square(self.output_holder - self.out_layer), reduction_indices=[1])) 35 | self.train_step = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(self.loss) 36 | self.init = tf.global_variables_initializer() 37 | self.run_config = tf.ConfigProto(device_count={'gpu': 0}) 38 | self.run_config.gpu_options.allow_growth=True 39 | self.sess = tf.Session(config=self.run_config) 40 | self.saver = tf.train.Saver() 41 | 42 | def train1(self, _input, _output): 43 | self.sess.run(self.init) 44 | for i in range(20000): 45 | self.sess.run(self.train_step, feed_dict={self.input_holder: _input, self.output_holder: _output}) 46 | if i % 50 == 0: 47 | print("迭代次数:"+str(i)) 48 | print(self.sess.run(self.loss, feed_dict={self.input_holder: _input, self.output_holder: _output})) 49 | # print(self.sess.run(self.out_layer, feed_dict={self.input_holder: _input, self.output_holder: _output})) 50 | '''if self.sess.run(self.loss, feed_dict={self.input_holder: _input, self.output_holder: _output}) < 50: 51 | self.saver.save(self.sess, "save/model.ckpt") 52 | break''' 53 | self.saver.save(self.sess, "save/model.ckpt") 54 | 55 | def predict(self, _input): 56 | f = open('predict_result.txt', 'w') 57 | for each_input in _input: 58 | each_input = each_input.reshape(1, len(each_input)) 59 | f.write(str(self.sess.run(self.out_layer, feed_dict={self.input_holder: each_input})).lstrip('[ ').rstrip(']')) 60 | f.write('\n') 61 | f.close() 62 | 63 | def load_nn(self): 64 | self.saver.restore(self.sess, "save/model.ckpt") 65 | 66 | 67 | 68 | if __name__=='__main__': 69 | # 训练数据 70 | input_arr = np.load("input_arr.npy") 71 | output_arr = np.load("output_arr.npy") 72 | 73 | # 测试数据 74 | test_input_arr = np.load("test_input_arr.npy") 75 | test_output_arr = np.load("test_output_arr.npy") 76 | 77 | input_arr = scale(input_arr) 78 | test_input_arr = scale(test_input_arr) 79 | model = Bpnn([23, 20, 18, 16, 14, 12, 10, 7, 5, 3, 1], 0.00025) 80 | #model.load_nn() 81 | model.train1(test_input_arr, test_output_arr) 82 | model.predict(test_input_arr) 83 | 84 | -------------------------------------------------------------------------------- /11.Ant Colony Algorithm.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import random 3 | import copy 4 | import time 5 | import sys 6 | import math 7 | import tkinter # //GUI模块 8 | import threading 9 | from functools import reduce 10 | 11 | # 参数 12 | ''' 13 | ALPHA:信息启发因子,值越大,则蚂蚁选择之前走过的路径可能性就越大 14 | ,值越小,则蚁群搜索范围就会减少,容易陷入局部最优 15 | BETA:Beta值越大,蚁群越就容易选择局部较短路径,这时算法收敛速度会 16 | 加快,但是随机性不高,容易得到局部的相对最优 17 | ''' 18 | (ALPHA, BETA, RHO, Q) = (1.0, 1.0, 0.5, 100.0) 19 | # 站点数,蚁群 20 | # 默认货车从数组中的第一个站点发出 21 | (city_num, ant_num) = (50, 50) 22 | distance_x = [ 23 | 158, 272, 176, 91, 550, 499, 267, 703, 408, 437, 431, 74, 532, 24 | 416, 626, 42, 221, 359, 163, 508, 229, 576, 147, 560, 115, 654, 25 | 757, 517, 64, 314, 675, 690, 391, 628, 87, 140, 705, 699, 258, 26 | 428, 614, 36, 360, 482, 666, 597, 209, 201, 492, 294] 27 | distance_y = [ 28 | 90, 395, 198, 131, 242, 556, 57, 401, 305, 421, 267, 105, 525, 29 | 381, 244, 330, 395, 169, 141, 380, 153, 442, 528, 329, 232, 48, 30 | 498, 265, 343, 120, 165, 50, 433, 63, 491, 275, 348, 222, 288, 31 | 490, 213, 524, 244, 114, 104, 552, 70, 425, 227, 331] 32 | #bi为实际单车数-单车需求量的偏差值,bi>0供大于求->装上货车,bi<0供不应求->卸下货车 33 | bi=[ 34 | 0,23,-4,17,-15,-9,21,20,-8,-30,-2,-3,2,-6,8,4,-2,-6,8,13,20,-6,3,-18,-29, 35 | 5,20,14,-6,1,-18,-3,-7,1,6,-3,9,4,17,25,23,10,-25,9,5,-16,8,1,-25,4] 36 | #MaxBike为货车最大负载量 37 | MaxBike=100 38 | # 站点距离和信息素 39 | distance_graph = [[0.0 for col in range(city_num)] for raw in range(city_num)] 40 | pheromone_graph = [[1.0 for col in range(city_num)] for raw in range(city_num)] 41 | 42 | 43 | # ----------- 蚂蚁 ----------- 44 | class Ant(object): 45 | 46 | # 初始化 47 | def __init__(self, ID): 48 | 49 | self.ID = ID # ID 50 | self.__clean_data() # 初始化蚂蚁 51 | 52 | # 初始数据 53 | def __clean_data(self): 54 | 55 | self.path = [] # 当前蚂蚁的路径 56 | self.total_distance = 0.0 # 当前路径的总距离 57 | self.move_count = 0 # 移动次数 58 | self.current_city = -1 # 当前停留的站点 59 | self.CurrentBike=0 # 当前货车上的单车数 60 | self.not_visited_city = [True for i in range(city_num)] #站点是否已经访问过 61 | self.open_table_city = [True for i in range(city_num)] # 探索站点的状态 62 | 63 | city_index = 0 # 初始出生点为第一个站点 64 | self.current_city = city_index 65 | self.path.append(city_index) 66 | self.not_visited_city[city_index] = False 67 | self.move_count = 1 68 | self.__calculate_open_table_city() 69 | 70 | #计算满足约束条件的备选列表 71 | def __calculate_open_table_city(self): 72 | for i in range(len(self.open_table_city)): 73 | if self.not_visited_city[i]==False:#过滤掉已经访问过的结点 74 | self.open_table_city[i]=False 75 | else: 76 | if (bi[i]>=0 and self.CurrentBike+bi[i]<=MaxBike) or (bi[i]<=0 and self.CurrentBike+bi[i]>=0): 77 | self.open_table_city[i]=True 78 | else: 79 | self.open_table_city[i] = False 80 | 81 | # 选择下一个城市 82 | def __choice_next_city(self): 83 | 84 | next_city = -1 85 | select_citys_prob = [0.0 for i in range(city_num)] # 存储去下个城市的概率 86 | total_prob = 0.0 87 | 88 | # 获取去下一个城市的概率 89 | for i in range(city_num): 90 | if self.open_table_city[i]: 91 | try: 92 | # 计算概率:与信息素浓度成正比,与距离成反比 93 | select_citys_prob[i] = pow(pheromone_graph[self.current_city][i], ALPHA) * pow( 94 | (1.0 / distance_graph[self.current_city][i]), BETA) 95 | total_prob += select_citys_prob[i] 96 | except ZeroDivisionError as e: 97 | print('Ant ID: {ID}, current city: {current}, target city: {target}'.format(ID=self.ID, 98 | current=self.current_city, 99 | target=i)) 100 | sys.exit(1) 101 | 102 | # 轮盘选择城市 103 | if total_prob > 0.0: 104 | # 产生一个随机概率,0.0-total_prob 105 | temp_prob = random.uniform(0.0, total_prob) 106 | for i in range(city_num): 107 | if self.open_table_city[i]: 108 | # 轮次相减 109 | temp_prob -= select_citys_prob[i] 110 | if temp_prob < 0.0: 111 | next_city = i 112 | break 113 | 114 | # 未从概率产生,顺序选择一个未访问城市 115 | # if next_city == -1: 116 | # for i in range(city_num): 117 | # if self.open_table_city[i]: 118 | # next_city = i 119 | # break 120 | 121 | if (next_city == -1): 122 | next_city = random.randint(0, city_num - 1) 123 | while ((self.open_table_city[next_city]) == False): # if==False,说明不可选择该站点 124 | next_city = random.randint(0, city_num - 1) 125 | 126 | # 返回下一个城市序号 127 | return next_city 128 | 129 | # 计算路径总距离 130 | def __cal_total_distance(self): 131 | 132 | temp_distance = 0.0 133 | 134 | for i in range(1, city_num): 135 | start, end = self.path[i], self.path[i - 1] 136 | temp_distance += distance_graph[start][end] 137 | 138 | # 回路 139 | end = self.path[0] 140 | temp_distance += distance_graph[start][end] 141 | self.total_distance = temp_distance 142 | 143 | # 移动操作 144 | def __move(self, next_city): 145 | 146 | self.path.append(next_city) 147 | self.not_visited_city[next_city] = False 148 | self.open_table_city[next_city] = False 149 | self.total_distance += distance_graph[self.current_city][next_city] 150 | self.current_city = next_city 151 | self.move_count += 1 152 | self.CurrentBike+=bi[next_city] 153 | 154 | # 搜索路径 155 | def search_path(self): 156 | 157 | # 初始化数据 158 | self.__clean_data() 159 | 160 | # 搜素路径,遍历完所有城市为止 161 | while self.move_count < city_num: 162 | # 移动到下一个城市 163 | self.__calculate_open_table_city() 164 | next_city = self.__choice_next_city() 165 | self.__move(next_city) 166 | 167 | # 计算路径总长度 168 | self.__cal_total_distance() 169 | 170 | 171 | # ----------- TSP问题 ----------- 172 | 173 | class TSP(object): 174 | 175 | def __init__(self, root, width=800, height=600, n=city_num): 176 | 177 | # 创建画布 178 | self.root = root 179 | self.width = width 180 | self.height = height 181 | # 站点数目初始化为city_num 182 | self.n = n 183 | # tkinter.Canvas 184 | self.canvas = tkinter.Canvas( 185 | root, 186 | width=self.width, 187 | height=self.height, 188 | bg="#EBEBEB", # 背景白色 189 | xscrollincrement=1, 190 | yscrollincrement=1 191 | ) 192 | self.canvas.pack(expand=tkinter.YES, fill=tkinter.BOTH) 193 | self.title("TSP蚁群算法(n:初始化 e:开始搜索 s:停止搜索 q:退出程序)") 194 | self.__r = 5 195 | self.__lock = threading.RLock() # 线程锁 196 | 197 | self.__bindEvents() 198 | self.new() 199 | 200 | # 计算站点之间的距离 201 | for i in range(city_num): 202 | for j in range(city_num): 203 | temp_distance = pow((distance_x[i] - distance_x[j]), 2) + pow((distance_y[i] - distance_y[j]), 2) 204 | temp_distance = pow(temp_distance, 0.5) 205 | distance_graph[i][j] = float(int(temp_distance + 0.5)) 206 | 207 | # 按键响应程序 208 | def __bindEvents(self): 209 | 210 | self.root.bind("q", self.quite) # 退出程序 211 | self.root.bind("n", self.new) # 初始化 212 | self.root.bind("e", self.search_path) # 开始搜索 213 | self.root.bind("s", self.stop) # 停止搜索 214 | 215 | # 更改标题 216 | def title(self, s): 217 | 218 | self.root.title(s) 219 | 220 | # 初始化 221 | def new(self, evt=None): 222 | 223 | # 停止线程 224 | self.__lock.acquire() 225 | self.__running = False 226 | self.__lock.release() 227 | 228 | self.clear() # 清除信息 229 | self.nodes = [] # 节点坐标 230 | self.nodes2 = [] # 节点对象 231 | 232 | # 初始化站点节点 233 | for i in range(len(distance_x)): 234 | # 在画布上随机初始坐标 235 | x = distance_x[i] 236 | y = distance_y[i] 237 | self.nodes.append((x, y)) 238 | # 生成节点椭圆,半径为self.__r 239 | if i!=0: 240 | node = self.canvas.create_oval(x - self.__r, 241 | y - self.__r, x + self.__r, y + self.__r, 242 | fill="green", # 填充绿色 243 | outline="#000000", # 轮廓白色 244 | tags="node", 245 | ) 246 | else: # 对出发点,标为红色 247 | node = self.canvas.create_oval(x - self.__r, 248 | y - self.__r, x + self.__r, y + self.__r, 249 | fill="#ff0000", # 填充红色 250 | outline="#000000", # 轮廓白色 251 | tags="node", 252 | ) 253 | self.nodes2.append(node) 254 | # 显示坐标 255 | # self.canvas.create_text(x, y - 10, # 使用create_text方法在坐标(302,77)处绘制文字 256 | # text='(' + str(x) + ',' + str(y) + ')', # 所绘制文字的内容 257 | # fill='black' # 所绘制文字的颜色为灰色 258 | # ) 259 | self.canvas.create_text(x, y - 10, # 使用create_text方法在坐标(302,77)处绘制文字 260 | text=str(i)+'('+str(bi[i])+')', # 所绘制文字的内容 261 | fill='black' # 所绘制文字的颜色为灰色 262 | ) 263 | 264 | # 顺序连接城市 265 | # self.line(range(city_num)) 266 | 267 | # 初始城市之间的距离和信息素 268 | for i in range(city_num): 269 | for j in range(city_num): 270 | pheromone_graph[i][j] = 1.0 271 | 272 | self.ants = [Ant(ID) for ID in range(ant_num)] # 初始蚁群 273 | self.best_ant = Ant(-1) # 初始最优解 274 | self.best_ant.total_distance = 1 << 31 # 初始最大距离 275 | self.iter = 1 # 初始化迭代次数 276 | 277 | # 将节点按order顺序连线 278 | def line(self, order): 279 | # 删除原线 280 | self.canvas.delete("line") 281 | 282 | def line2(i1, i2): 283 | p1, p2 = self.nodes[i1], self.nodes[i2] 284 | self.canvas.create_line(p1, p2, fill="#000000", tags="line") 285 | return i2 286 | 287 | # order[-1]为初始值 288 | reduce(line2, order, order[-1]) 289 | 290 | # 清除画布 291 | def clear(self): 292 | for item in self.canvas.find_all(): 293 | self.canvas.delete(item) 294 | 295 | # 退出程序 296 | def quite(self, evt): 297 | self.__lock.acquire() 298 | self.__running = False 299 | self.__lock.release() 300 | self.root.destroy() 301 | print(u"\n程序已退出...") 302 | sys.exit() 303 | 304 | # 停止搜索 305 | def stop(self, evt): 306 | self.__lock.acquire() 307 | self.__running = False 308 | self.__lock.release() 309 | 310 | # 开始搜索 311 | def search_path(self, evt=None): 312 | 313 | # 开启线程 314 | self.__lock.acquire() 315 | self.__running = True 316 | self.__lock.release() 317 | 318 | while self.__running: 319 | # 遍历每一只蚂蚁 320 | for ant in self.ants: 321 | # 搜索一条路径 322 | ant.search_path() 323 | # 与当前最优蚂蚁比较 324 | if ant.total_distance < self.best_ant.total_distance: 325 | # 更新最优解 326 | self.best_ant = copy.deepcopy(ant) 327 | # 更新信息素 328 | self.__update_pheromone_gragh() 329 | print(u"迭代次数:", self.iter, u"最佳路径总距离:", int(self.best_ant.total_distance)) 330 | print(u"最佳路径:") 331 | for i in range(len(self.best_ant.path)): 332 | print(self.best_ant.path[i],end=" ") 333 | print('\n') 334 | # 连线 335 | self.line(self.best_ant.path) 336 | # 设置标题 337 | self.title("TSP蚁群算法(n:随机初始 e:开始搜索 s:停止搜索 q:退出程序) 迭代次数: %d" % self.iter) 338 | # 更新画布 339 | self.canvas.update() 340 | self.iter += 1 341 | 342 | # 更新信息素 343 | def __update_pheromone_gragh(self): 344 | 345 | # 获取每只蚂蚁在其路径上留下的信息素 346 | temp_pheromone = [[0.0 for col in range(city_num)] for raw in range(city_num)] 347 | for ant in self.ants: 348 | for i in range(1, city_num): 349 | start, end = ant.path[i - 1], ant.path[i] 350 | # 在路径上的每两个相邻城市间留下信息素,与路径总距离反比 351 | temp_pheromone[start][end] += Q / ant.total_distance 352 | temp_pheromone[end][start] = temp_pheromone[start][end] 353 | 354 | # 更新所有城市之间的信息素,旧信息素衰减加上新迭代信息素 355 | for i in range(city_num): 356 | for j in range(city_num): 357 | pheromone_graph[i][j] = pheromone_graph[i][j] * RHO + temp_pheromone[i][j] 358 | 359 | # 主循环 360 | def mainloop(self): 361 | self.root.mainloop() 362 | 363 | 364 | # ----------- 程序的入口处 ----------- 365 | 366 | if __name__ == '__main__': 367 | TSP(tkinter.Tk()).mainloop() 368 | --------------------------------------------------------------------------------