前提・実現したいこと
pythonで巡回セールスマンの遺伝的アルゴリズムによる解決をしたいです。
Qiitaで見つけたプログラムを実行しているのですが、どうもエリート保存がうまくいきません。
次のループに行くときに最善の値が引き継げていないです。
どのように変更すればいいでしょうか。
教えていただければ幸いです。
発生している問題・エラーメッセージ
エリート保存がうまくいかない(突然変異によって結果が改悪されている?)
該当のソースコード
Python
1 2# coding:utf-8 3 4import random as rnd 5import matplotlib.pyplot as plt 6import math 7import copy 8 9 10def generator(num, pop_num): 11 """ 都市を初期生成 """ 12 13 # 範囲指定 14 x_range = 200 15 y_range = 200 16 17 x_coordinate = [rnd.randint(0, x_range) for _ in range(num)] 18 y_coordinate = [rnd.randint(0, y_range) for _ in range(num)] 19 20 coordinate = [[x_coordinate[i], y_coordinate[i]] for i in range(num)] 21 22 # keyが都市の番号、valueが座標値の辞書作成。 23 position_info = {} 24 for i in range(num): 25 position_info[i] = coordinate[i] 26 27 # 初期の巡回順序生成 28 select_num = [i for i in range(num)] 29 all_route = [rnd.sample(select_num, num) for _ in range(pop_num)] 30 31 return position_info, all_route 32 33 34def evaluate(position_info, all_route, loop=0): 35 """ ユークリッド距離の総和を計算し評価値とする。 """ 36 37 evaluate_value = [] 38 for i in range(len(all_route)): 39 temp_evaluate_value = [] 40 x_coordinate = [position_info[all_route[i][x]][0] for x in range(len(all_route[i]))] 41 y_coordinate = [position_info[all_route[i][y]][1] for y in range(len(all_route[i]))] 42 for j in range(len(all_route[i])): 43 if j == len(all_route[i]) - 1: 44 distance = math.sqrt( 45 pow((x_coordinate[j] - x_coordinate[0]), 2) + pow((y_coordinate[j] - y_coordinate[0]), 2)) 46 else: 47 distance = math.sqrt( 48 pow((x_coordinate[j] - x_coordinate[j + 1]), 2) + pow((y_coordinate[j] - y_coordinate[j + 1]), 2)) 49 temp_evaluate_value.append(distance) 50 evaluate_value.append(sum(temp_evaluate_value)) 51 52 # 一番優秀な個体をmatplotで描画 53 excellent_evaluate_value = min(evaluate_value) 54 draw_pop_index = evaluate_value.index(excellent_evaluate_value) 55 56 show_route(position_info, all_route[draw_pop_index],int(excellent_evaluate_value), loop=loop + 1) 57 58 return evaluate_value 59 60 61def selection(all_route, evaluate_value, tournament_select_num, tournament_size, elite_select_num, ascending=False): 62 """ トーナメント選択とエリート保存を行う""" 63 64 select_pop = [] 65 elite_pop = [] 66 # トーナメント選択 67 while True: 68 select = rnd.sample(evaluate_value, tournament_size) 69 select.sort(reverse=ascending) 70 for i in range(tournament_select_num): 71 value = select[i] 72 index = evaluate_value.index(value) 73 select_pop.append(all_route[index]) 74 75 # 個体数の半数個選択するまで実行 76 if len(select_pop) >= len(all_route) / 2: 77 break 78 79 # エリート保存 80 sort_evaluate_value = copy.deepcopy(evaluate_value) 81 sort_evaluate_value.sort(reverse=ascending) 82 for i in range(elite_select_num): 83 value = sort_evaluate_value[i] 84 index = evaluate_value.index(value) 85 elite_pop.append(all_route[index]) 86 87 return select_pop, elite_pop 88 89 90def crossover(select_pop, crossover_prob): 91 ''' 確率的に順序交叉を実行する ''' 92 93 cross_pop = rnd.sample(select_pop, 2) 94 pop_1 = cross_pop[0] 95 pop_2 = cross_pop[1] 96 97 check_prob = rnd.randint(1, 100) 98 if check_prob <= crossover_prob: 99 100 # 順序交叉 101 new_pop_1 = [] 102 cut_index = rnd.randint(1, len(pop_1) - 2) 103 new_pop_1.extend(pop_1[:cut_index]) 104 for i in range(len(pop_1)): 105 if pop_2[i] not in new_pop_1: 106 new_pop_1.append(pop_2[i]) 107 108 new_pop_2 = [] 109 new_pop_2.extend(pop_1[cut_index:]) 110 for i in range(len(pop_1)): 111 if pop_2[i] not in new_pop_2: 112 new_pop_2.append(pop_2[i]) 113 114 return new_pop_1, new_pop_2 115 116 else: 117 return pop_1, pop_2 118 119 120def mutation(pop, mutation_prob): 121 """ 循環経路の順番をランダムで入れ替える """ 122 123 check_prob = rnd.randint(0, 100) 124 125 if check_prob <= mutation_prob: 126 select_num = [i for i in range(num)] 127 select_index = rnd.sample(select_num, 2) 128 129 a = pop[select_index[0]] 130 b = pop[select_index[1]] 131 pop[select_index[1]] = a 132 pop[select_index[0]] = b 133 134 return pop 135 136 137def show_route(position_info, route, excellent_evaluate_value, loop=0): 138 """ matplotlibで循環経路を描画 """ 139 140 x_coordinate = [position_info[route[i]][0] for i in range(len(route))] 141 y_coordinate = [position_info[route[i]][1] for i in range(len(route))] 142 x_coordinate.append(position_info[route[0]][0]) 143 y_coordinate.append(position_info[route[0]][1]) 144 145 plt.scatter(x_coordinate, y_coordinate) 146 plt.plot(x_coordinate, y_coordinate, label=excellent_evaluate_value) 147 plt.title("Generation: {}".format(loop)) 148 plt.legend() 149 150 plt.savefig("tsp{}".format(loop)) # pngとして保存。カレントディレクトリにimgフォルダを置く必要あり。 151 plt.show() 152 153 154# 初期生成時のパラメータ 155num = 20 # 都市の数 156pop_num = 200 # 個体数 157generation_num = 200 # 世代数 158 159# 選択のパラメータ 160tournament_size = 10 161tournament_select_num = 2 162elite_select_num = 1 163 164# 交叉の確率 165crossover_prob = 0 166 167# 突然変異の確率 168mutation_prob = 3 169 170 171# 初期生成 172position_info, all_route = generator(num, pop_num) 173 174# 評価 175evaluate_value = evaluate(position_info, all_route) 176 177for loop in range(generation_num): 178 # 選択 179 select_pop, elite_pop = selection( 180 all_route, evaluate_value, tournament_select_num, tournament_size, elite_select_num, ascending=False) 181 182 # 選択した個体の中から2個体選択し交叉や突然変異を適用する。 183 next_pop = [] 184 while True: 185 # 交叉pop1,pop2はselectpopから選んだ 186 pop_1, pop_2 = crossover(select_pop, crossover_prob) 187 188 # 突然変異 189 190 pop_1 = mutation(pop_1, mutation_prob) 191 pop_2 = mutation(pop_2, mutation_prob) 192 193 next_pop.append(pop_1) 194 next_pop.append(pop_2) 195 196 if len(next_pop) >= pop_num - elite_select_num: 197 break 198 199 # エリート主義。優良個体を次世代へ継承。 200 next_pop.extend(elite_pop) 201 202 203 # 評価 204 evaluate_value = evaluate(position_info, next_pop, loop=loop + 1) 205 206 207 # 更新 208 all_route = next_pop
試したこと
エリート保存をする場所を変えたりしましたが、うまくいきませんでした。。。
補足情報(FW/ツールのバージョンなど)
ここにより詳細な情報を記載してください。
回答1件
あなたの回答
tips
プレビュー