Κοινή χρήση τεχνολογίας

Python34 Genetic Algorithm (GA)

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

1. Ιστορικό ανάπτυξης

Ο γενετικός αλγόριθμος (GA) είναι ένας αλγόριθμος βελτιστοποίησης εμπνευσμένος από τη φυσική επιλογή και τη γενετική. Προτάθηκε για πρώτη φορά από τον Αμερικανό μελετητή John Holland στη δεκαετία του 1970, με στόχο να μελετήσει την προσαρμοστικότητα σε φυσικά συστήματα και να εφαρμοστεί σε προβλήματα βελτιστοποίησης στην επιστήμη των υπολογιστών.

Βασικό ιστορικό ανάπτυξης
  • 1975: Ο John Holland πρότεινε για πρώτη φορά την έννοια του γενετικού αλγόριθμου στο βιβλίο του «Adaptation in Natural and Artificial Systems».

  • δεκαετία του 1980: Οι γενετικοί αλγόριθμοι άρχισαν να χρησιμοποιούνται σε πεδία όπως η βελτιστοποίηση συναρτήσεων και η συνδυαστική βελτιστοποίηση και σταδιακά τράβηξαν την προσοχή.

  • δεκαετία του 1990: Με τη βελτίωση της υπολογιστικής ισχύος των υπολογιστών, οι γενετικοί αλγόριθμοι έχουν χρησιμοποιηθεί ευρέως στη μηχανική, την οικονομία, τη βιολογία και άλλους τομείς.

  • Δεκαετία 2000 έως σήμερα: Η θεωρία και η εφαρμογή των γενετικών αλγορίθμων έχουν αναπτυχθεί περαιτέρω και έχουν προκύψει μια ποικιλία βελτιωμένων αλγορίθμων, όπως π.χ.遗传编程(Γενετικός Προγραμματισμός)差分进化(Διαφορική Εξέλιξη) κ.λπ.

2. Μαθηματικές αρχές

Ο γενετικός αλγόριθμος είναι μια μέθοδος τυχαίας αναζήτησης που βασίζεται στη φυσική επιλογή και τη γενετική Η βασική του ιδέα είναι να προσομοιώσει τη διαδικασία της βιολογικής εξέλιξης.επιλέγωσταυρόςκαιΜεταλλάξειςΛειτουργία, δημιουργεί συνεχώς μια νέα γενιά πληθυσμών, προσεγγίζοντας έτσι σταδιακά τη βέλτιστη λύση.

Βασικά βήματα γενετικού αλγορίθμου
  1. αρχικοποίηση: Δημιουργήστε τυχαία τον αρχικό πληθυσμό.

  2. επιλέγω: Επιλέξτε καλύτερα άτομα με βάση τη λειτουργία φυσικής κατάστασης.

  3. σταυρός: Δημιουργήστε ένα νέο άτομο ανταλλάσσοντας μέρος των γονιδίων του γονικού ατόμου.

  4. Μεταλλάξεις: Τυχαία αλλαγή ορισμένων γονιδίων ενός ατόμου.

  5. επαναλέγω: Επαναλάβετε τις διαδικασίες επιλογής, διασταύρωσης και μετάλλαξης μέχρι να εκπληρωθεί η συνθήκη τερματισμού.

μαθηματική περιγραφή

Ας υποθέσουμε ότι το μέγεθος του πληθυσμού είναι N και το μήκος του χρωμοσώματος κάθε ατόμου είναι L. Η μαθηματική διαδικασία του γενετικού αλγορίθμου είναι η εξής:

  1. αρχικοποίηση: Δημιουργία πληθυσμού , πού είναι το χρωμόσωμα.

  2. Υπολογισμός φυσικής κατάστασης: Υπολογίστε την αξία φυσικής κατάστασης κάθε ατόμου.

  3. επιλέγω: Επιλέξτε άτομα με βάση τις τιμές φυσικής κατάστασης Οι συνήθεις μέθοδοι που χρησιμοποιούνται περιλαμβάνουν την επιλογή ρουλέτας, την επιλογή τουρνουά κ.λπ.

  4. σταυρός: Επιλέξτε ορισμένα άτομα για λειτουργία crossover για να δημιουργήσετε νέα άτομα.

  5. Μεταλλάξεις: Εκτελέστε λειτουργίες μετάλλαξης σε ορισμένα νέα άτομα για να δημιουργήσετε μεταλλαγμένα άτομα.

  6. ενημέρωση πληθυσμού: Αντικαταστήστε τα παλιά άτομα με νέα άτομα για να σχηματίσετε μια νέα γενιά πληθυσμού.

  7. Προϋπόθεση τερματισμού: Εάν επιτευχθεί η προκαθορισμένη συνθήκη τερματισμού (όπως ο αριθμός επαναλήψεων ή το κατώφλι καταλληλότητας), η βέλτιστη λύση προκύπτει.

3. Σενάρια εφαρμογής

Οι γενετικοί αλγόριθμοι έχουν χρησιμοποιηθεί ευρέως σε πολλούς τομείς λόγω της προσαρμοστικότητας και της ευρωστίας τους:

Μηχανική βελτιστοποίηση
  • Δομική βελτιστοποίηση: Σχεδιάστε ελαφριά και υψηλής αντοχής δομή.

  • Βελτιστοποίηση παραμέτρων: Προσαρμόστε τις παραμέτρους του συστήματος για βέλτιστη απόδοση.

Οικονομικά και Χρηματοοικονομικά
  • Βελτιστοποίηση χαρτοφυλακίου: Κατανομή επενδυτικών περιουσιακών στοιχείων για μεγιστοποίηση των αποδόσεων.

  • πρόβλεψη αγοράς: Προβλέψτε τις τιμές των μετοχών και τις τάσεις της αγοράς.

βιοπληροφορικής
  • Σύγκριση αλληλουχίας γονιδίων: Συγκρίνετε και αναλύστε αλληλουχίες DNA.

  • Πρόβλεψη δομής πρωτεΐνης: Προβλέψτε την τρισδιάστατη δομή μιας πρωτεΐνης.

μηχανική μάθηση
  • Εκπαίδευση νευρωνικών δικτύων: Βελτιστοποιήστε τα βάρη και τη δομή των νευρωνικών δικτύων.

  • Επιλογή χαρακτηριστικών: Επιλέξτε τα χαρακτηριστικά που είναι πιο ωφέλιμα για ταξινόμηση ή παλινδρόμηση.

4. Οπτική υλοποίηση παραδειγμάτων Python

εικόνα

Το ακόλουθο παράδειγμα κώδικα υλοποιεί έναν γενετικό αλγόριθμο για την επίλυση του προβλήματος του πλανόδιου πωλητή.旅行商问题(TSP) είναι ένα κλασικό πρόβλημα συνδυαστικής βελτιστοποίησης που στοχεύει στην εύρεση της συντομότερης διαδρομής για έναν ταξιδιώτη πωλητή για να επισκεφθεί κάθε μία από ένα δεδομένο σύνολο πόλεων ακριβώς μία φορά και τελικά να επιστρέψει στην πόλη εκκίνησης, δηλαδή να ελαχιστοποιήσει τη συνολική απόσταση ταξιδιού ή το κόστος, ευρέως χρησιμοποιούνται στα logistics, στον προγραμματισμό παραγωγής και σε άλλους τομείς.

Αρχικά ορίζουμε όλες τις επαρχιακές πρωτεύουσες στην Κίνα (συμπεριλαμβανομένωνΤαϊπέι, πρωτεύουσα της επαρχίας Ταϊβάν της Κίνας) και τα δεδομένα συντεταγμένων και η χρήση τους哈夫曼公式Υπολογίστε την απόσταση μεταξύ δύο σημείων και μετά περάστε遗传算法Δημιουργήστε έναν αρχικό πληθυσμό, αναπαραγωγή, μετάλλαξη και δημιουργία της επόμενης γενιάς, βελτιστοποιήστε συνεχώς τη διαδρομή και τέλος καταγράψτε την απόσταση και την αντίστοιχη διαδρομή της συντομότερης διαδρομής σε κάθε γενιά, βρείτε τη συντομότερη διαδρομή σε όλες τις επαναλήψεις και εμφανίστε την οπτικά στον χάρτηΌλες οι τοποθεσίες της πόληςΗ φυσική κατάσταση αλλάζει με τον αριθμό των επαναλήψεων Εκτός από τη βέλτιστη διαδρομή, το τελικό αποτέλεσμα δείχνει τη συντομότερη διαδρομή από το Chongqing σε όλες τις πόλεις και τη συνολική απόσταση. Συνολικά δύο φορές εκπαίδευσης, ο πρώτος αριθμός επανάληψης είναι 2000, ο χρόνος εκτέλεσης είναι περίπου 3 λεπτά, ο δεύτερος αριθμός επανάληψης ορίζεται σε 20000, ο χρόνος εκτέλεσης είναι περίπου 15 λεπτά.

Για να συνοψίσουμε σε μια φράση: ξεκινώντας από το Chongqing, ταξιδέψτε σε όλες τις επαρχιακές πρωτεύουσες της Κίνας και χρησιμοποιήστε γενετικούς αλγόριθμους για να βρείτε το συντομότερο μονοπάτι. Ακολουθεί η υλοποίηση του κώδικα:

  1. import numpy as np
  2. import matplotlib.pyplot as plt
  3. from mpl_toolkits.basemap import Basemap
  4. import random
  5. from math import radians, sin, cos, sqrt, atan2
  6. # 设置随机种子以保证结果可重复
  7. random.seed(42)
  8. np.random.seed(42)
  9. # 定义城市和坐标列表,包括台北
  10. cities = {
  11.     "北京": (39.9042116.4074),
  12.     "天津": (39.3434117.3616),
  13.     "石家庄": (38.0428114.5149),
  14.     "太原": (37.8706112.5489),
  15.     "呼和浩特": (40.8426111.7511),
  16.     "沈阳": (41.8057123.4315),
  17.     "长春": (43.8171125.3235),
  18.     "哈尔滨": (45.8038126.5349),
  19.     "上海": (31.2304121.4737),
  20.     "南京": (32.0603118.7969),
  21.     "杭州": (30.2741120.1551),
  22.     "合肥": (31.8206117.2272),
  23.     "福州": (26.0745119.2965),
  24.     "南昌": (28.6820115.8579),
  25.     "济南": (36.6512117.1201),
  26.     "郑州": (34.7466113.6254),
  27.     "武汉": (30.5928114.3055),
  28.     "长沙": (28.2282112.9388),
  29.     "广州": (23.1291113.2644),
  30.     "南宁": (22.8170108.3665),
  31.     "海口": (20.0174110.3492),
  32.     "重庆": (29.5638106.5507),
  33.     "成都": (30.5728104.0668),
  34.     "贵阳": (26.6477106.6302),
  35.     "昆明": (25.0460102.7097),
  36.     "拉萨": (29.652091.1721),
  37.     "西安": (34.3416108.9398),
  38.     "兰州": (36.0611103.8343),
  39.     "西宁": (36.6171101.7782),
  40.     "银川": (38.4872106.2309),
  41.     "乌鲁木齐": (43.825687.6168),
  42.     "台北": (25.032969121.565418)
  43. }
  44. # 城市列表和坐标
  45. city_names = list(cities.keys())
  46. locations = np.array(list(cities.values()))
  47. chongqing_index = city_names.index("重庆")
  48. # 使用哈夫曼公式计算两点间的距离
  49. def haversine(lat1, lon1, lat2, lon2):
  50.     R = 6371.0  # 地球半径,单位为公里
  51.     dlat = radians(lat2 - lat1)
  52.     dlon = radians(lon1 - lon2)
  53.     a = sin(dlat / 2)**2 + cos(radians(lat1)) * cos(radians(lat2)) * sin(dlon / 2)**2
  54.     c = 2 * atan2(sqrt(a), sqrt(1 - a))
  55.     distance = R * c
  56.     return distance
  57. # 计算路径总距离的函数,单位为公里
  58. def calculate_distance(path):
  59.     return sum(haversine(locations[path[i]][0], locations[path[i]][1], locations[path[i + 1]][0], locations[path[i + 1]][1]) for i in range(len(path) - 1))
  60. # 创建初始种群
  61. def create_initial_population(size, num_cities):
  62.     population = []
  63.     for _ in range(size):
  64.         individual = random.sample(range(num_cities), num_cities)
  65.         # 确保重庆为起点
  66.         individual.remove(chongqing_index)
  67.         individual.insert(0, chongqing_index)
  68.         population.append(individual)
  69.     return population
  70. # 对种群进行排名
  71. def rank_population(population):
  72.     # 按照路径总距离对种群进行排序
  73.     return sorted([(i, calculate_distance(individual)) for i, individual in enumerate(population)], key=lambda x: x[1])
  74. # 选择交配池
  75. def select_mating_pool(population, ranked_pop, elite_size):
  76.     # 选择排名前elite_size的个体作为交配池
  77.     return [population[ranked_pop[i][0]] for i in range(elite_size)]
  78. # 繁殖新个体
  79. def breed(parent1, parent2):
  80.     # 繁殖两个父母生成新个体
  81.     geneA = int(random.random() * (len(parent1) - 1)) + 1
  82.     geneB = int(random.random() * (len(parent1) - 1)) + 1
  83.     start_gene = min(geneA, geneB)
  84.     end_gene = max(geneA, geneB)
  85.     child = parent1[:start_gene] + parent2[start_gene:end_gene] + parent1[end_gene:]
  86.     child = list(dict.fromkeys(child))
  87.     missing = set(range(len(parent1))) - set(child)
  88.     for m in missing:
  89.         child.append(m)
  90.     # 确保重庆为起点
  91.     child.remove(chongqing_index)
  92.     child.insert(0, chongqing_index)
  93.     return child
  94. # 突变个体
  95. def mutate(individual, mutation_rate):
  96.     for swapped in range(1, len(individual) - 1):
  97.         if random.random() < mutation_rate:
  98.             swap_with = int(random.random() * (len(individual) - 1)) + 1
  99.             individual[swapped], individual[swap_with= individual[swap_with], individual[swapped]
  100.     return individual
  101. # 生成下一代
  102. def next_generation(current_gen, elite_size, mutation_rate):
  103.     ranked_pop = rank_population(current_gen)
  104.     mating_pool = select_mating_pool(current_gen, ranked_pop, elite_size)
  105.     children = []
  106.     length = len(mating_pool) - elite_size
  107.     pool = random.sample(mating_pool, len(mating_pool))
  108.     for i in range(elite_size):
  109.         children.append(mating_pool[i])
  110.     for i in range(length):
  111.         child = breed(pool[i], pool[len(mating_pool)-i-1])
  112.         children.append(child)
  113.     next_gen = [mutate(ind, mutation_rate) for ind in children]
  114.     return next_gen
  115. # 遗传算法主函数
  116. def genetic_algorithm(population, pop_size, elite_size, mutation_rate, generations):
  117.     pop = create_initial_population(pop_size, len(population))
  118.     progress = [(0, rank_population(pop)[0][1], pop[0])]  # 记录每代的最短距离和代数
  119.     for i in range(generations):
  120.         pop = next_generation(pop, elite_size, mutation_rate)
  121.         best_route_index = rank_population(pop)[0][0]
  122.         best_distance = rank_population(pop)[0][1]
  123.         progress.append((i + 1, best_distance, pop[best_route_index]))
  124.     best_route_index = rank_population(pop)[0][0]
  125.     best_route = pop[best_route_index]
  126.     return best_route, progress
  127. # 调整参数
  128. pop_size = 500       # 增加种群大小
  129. elite_size = 100     # 增加精英比例
  130. mutation_rate = 0.005 # 降低突变率
  131. generations = 20000   # 增加迭代次数
  132. # 运行遗传算法
  133. best_route, progress = genetic_algorithm(city_names, pop_size, elite_size, mutation_rate, generations)
  134. # 找到最短距离及其对应的代数
  135. min_distance = min(progress, key=lambda x: x[1])
  136. best_generation = min_distance[0]
  137. best_distance = min_distance[1]
  138. # 图1:地图上显示城市位置
  139. fig1, ax1 = plt.subplots(figsize=(1010))
  140. m1 = Basemap(projection='merc', llcrnrlat=18, urcrnrlat=50, llcrnrlon=80, urcrnrlon=135, resolution='l', ax=ax1)
  141. m1.drawcoastlines()
  142. m1.drawcountries()
  143. m1.fillcontinents(color='lightgray', lake_color='aqua')
  144. m1.drawmapboundary(fill_color='aqua')
  145. for i, (lat, lon) in enumerate(locations):
  146.     x, y = m1(lon, lat)
  147.     m1.plot(x, y, 'bo')
  148.     ax1.text(x, y, str(i), fontsize=8)
  149. ax1.set_title('City Locations')
  150. plt.show()
  151. # 图2:适应度随迭代次数变化
  152. fig2, ax2 = plt.subplots(figsize=(105))
  153. ax2.plot([x[1for x in progress])
  154. ax2.set_ylabel('Distance (km)')
  155. ax2.set_xlabel('Generation')
  156. ax2.set_title('Fitness over Iterations')
  157. # 在图中标注最短距离和对应代数
  158. ax2.annotate(f'Gen: {best_generation}nDist: {best_distance:.2f} km'
  159.              xy=(best_generation, best_distance), 
  160.              xytext=(best_generation, best_distance + 100),
  161.              arrowprops=dict(facecolor='red', shrink=0.05))
  162. plt.show()
  163. # 图3:显示最优路径
  164. fig3, ax3 = plt.subplots(figsize=(1010))
  165. m2 = Basemap(projection='merc', llcrnrlat=18, urcrnrlat=50, llcrnrlon=80, urcrnrlon=135, resolution='l', ax=ax3)
  166. m2.drawcoastlines()
  167. m2.drawcountries()
  168. m2.fillcontinents(color='lightgray', lake_color='aqua')
  169. m2.drawmapboundary(fill_color='aqua')
  170. # 绘制最优路径和有向箭头
  171. for i in range(len(best_route) - 1):
  172.     x1, y1 = m2(locations[best_route[i]][1], locations[best_route[i]][0])
  173.     x2, y2 = m2(locations[best_route[i + 1]][1], locations[best_route[i + 1]][0])
  174.     m2.plot([x1, x2], [y1, y2], color='g', linewidth=1, marker='o')
  175. # 只添加一个代表方向的箭头
  176. mid_index = len(best_route) // 2
  177. mid_x1, mid_y1 = m2(locations[best_route[mid_index]][1], locations[best_route[mid_index]][0])
  178. mid_x2, mid_y2 = m2(locations[best_route[mid_index + 1]][1], locations[best_route[mid_index + 1]][0])
  179. ax3.annotate('', xy=(mid_x2, mid_y2), xytext=(mid_x1, mid_y1), arrowprops=dict(facecolor='blue', shrink=0.05))
  180. # 在最优路径图上绘制城市位置
  181. for i, (lat, lon) in enumerate(locations):
  182.     x, y = m2(lon, lat)
  183.     m2.plot(x, y, 'bo')
  184.     ax3.text(x, y, str(i), fontsize=8)
  185. # 添加起点和终点标记
  186. start_x, start_y = m2(locations[best_route[0]][1], locations[best_route[0]][0])
  187. end_x, end_y = m2(locations[best_route[-1]][1], locations[best_route[-1]][0])
  188. ax3.plot(start_x, start_y, marker='^', color='red', markersize=15, label='Start (Chongqing)')  # 起点
  189. ax3.plot(end_x, end_y, marker='*', color='blue', markersize=15, label='End')   # 终点
  190. # 添加总距离的图例
  191. ax3.legend(title=f'Total Distance: {best_distance:.2f} km')
  192. ax3.set_title('Optimal Path')
  193. plt.show()

Οπτικοποίηση τοποθεσίας όλων των επαρχιακών πρωτευουσών στην Κίνα:

εικόνα

Ο αριθμός των επαναλήψεων είναι 2.000 (η μικρότερη απόσταση είναι 31594 χιλιόμετρα):

Βρείτε την επανάληψη της συντομότερης διαδρομής στη διαδικασία ιστορικής επανάληψης και οραματιστείτε τη συντομότερη διαδρομή.

εικόνα

εικόνα

Περίπτωση 2: Ο αριθμός των επαναλήψεων είναι 20.000 (η μικρότερη απόσταση που επιτυγχάνεται είναι 29.768 χιλιόμετρα)

Βρείτε την επανάληψη με τη συντομότερη διαδρομή στη διαδικασία ιστορικής επανάληψης και οραματιστείτε τη συντομότερη διαδρομή για αυτήν την επανάληψη.

εικόνα

εικόνα

Το παραπάνω περιεχόμενο συνοψίζεται από το Διαδίκτυο, εάν είναι χρήσιμο, προωθήστε το την επόμενη φορά.