Teknologian jakaminen

Python34 Genetic Algorithm (GA)

2024-07-12

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

1. Kehityshistoria

Genetic Algorithm (GA) on optimointialgoritmi, joka on saanut inspiraationsa luonnollisesta valinnasta ja genetiikasta. Amerikkalainen tutkija John Holland ehdotti sitä ensimmäisen kerran 1970-luvulla, ja sen tavoitteena oli tutkia sopeutumiskykyä luonnollisissa järjestelmissä ja sitä sovellettiin tietojenkäsittelytieteen optimointiongelmiin.

Keskeinen kehityshistoria
  • 1975: John Holland ehdotti ensimmäisen kerran geneettisen algoritmin käsitettä kirjassaan "Adaptation in Natural and Artificial Systems".

  • 1980-luku: Geneettisiä algoritmeja alettiin käyttää sellaisilla aloilla kuin toimintojen optimointi ja kombinatorinen optimointi, ja ne herättivät vähitellen huomiota.

  • 1990-luku: Tietokoneiden laskentatehon parantuessa geneettisiä algoritmeja on käytetty laajalti tekniikassa, taloudessa, biologiassa ja muilla aloilla.

  • 2000-luvulta nykypäivään: Geneettisten algoritmien teoria ja sovellus ovat kehittyneet edelleen, ja useita parannettuja algoritmeja on syntynyt, kuten esim.遗传编程(Geneettinen ohjelmointi).差分进化(Differential Evolution) jne.

2. Matemaattiset periaatteet

Geneettinen algoritmi on luonnonvalintaan ja genetiikkaan perustuva satunnaishakumenetelmä. Sen perusideana on simuloida biologista evoluutioprosessia.valitaylittääjaMutaatiotKäyttö, jatkuvasti luoda uuden sukupolven populaatioita, jolloin vähitellen lähestyy optimaalista ratkaisua.

Geneettisen algoritmin perusvaiheet
  1. alustus: Luo alkupopulaatio satunnaisesti.

  2. valita: Valitse parempia yksilöitä kuntotoiminnan perusteella.

  3. ylittää: Luo uusi yksilö vaihtamalla osa vanhemman yksilön geeneistä.

  4. Mutaatiot: Muuta satunnaisesti joitain yksilön geenejä.

  5. Toistaa: Toista valinta-, jako- ja mutaatioprosessit, kunnes lopetusehto täyttyy.

matemaattinen kuvaus

Oletetaan, että populaation koko on N ja kunkin yksilön kromosomin pituus on L. Geneettisen algoritmin matemaattinen prosessi on seuraava:

  1. alustus: Luo populaatio, missä on kromosomi.

  2. Kuntolaskenta: Laske jokaisen henkilön kunto-arvo.

  3. valita: Valitse yksilöt kuntoarvojen perusteella. Yleisesti käytettyjä menetelmiä ovat ruletin valinta, turnausvalinta jne.

  4. ylittää: Valitse joitakin yksilöitä jakotoimintoa varten luodaksesi uusia yksilöitä.

  5. Mutaatiot: Suorita mutaatiotoimenpiteitä joillekin uusille yksilöille mutatoituneiden yksilöiden luomiseksi.

  6. päivittää väestöä: Korvaa vanhat yksilöt uusilla yksilöillä uuden sukupolven muodostamiseksi.

  7. Päättymisehto: Jos esiasetettu lopetusehto (kuten iteraatioiden määrä tai kuntokynnys) saavutetaan, tulostetaan optimaalinen ratkaisu.

3. Sovellusskenaariot

Geneettisiä algoritmeja on käytetty laajalti monilla aloilla niiden mukautuvuuden ja kestävyyden vuoksi:

Tekninen optimointi
  • Rakenneoptimointi: Suunnittele kevyt ja luja rakenne.

  • Parametrien optimointi: Säädä järjestelmän parametreja optimaalisen suorituskyvyn saavuttamiseksi.

Talous ja rahoitus
  • Portfolion optimointi: Kohdista sijoitusomaisuutta tuoton maksimoimiseksi.

  • markkinoiden ennuste: Ennusta osakekursseja ja markkinatrendejä.

bioinformatiikka
  • Geenisekvenssien vertailu: Vertaa ja analysoi DNA-sekvenssejä.

  • Proteiinirakenteen ennuste: Ennusta proteiinin kolmiulotteinen rakenne.

koneoppimista
  • Neuroverkkokoulutus: Optimoi hermoverkkojen painot ja rakenne.

  • Ominaisuuden valinta: Valitse ominaisuudet, joista on eniten hyötyä luokittelussa tai regressiossa.

4. Python-esimerkkien visuaalinen toteutus

kuva

Seuraava koodiesimerkki toteuttaa geneettisen algoritmin matkustavan myyjän ongelman ratkaisemiseksi.旅行商问题(TSP) on klassinen kombinatorinen optimointitehtävä, jonka tavoitteena on löytää lyhin reitti, jolla matkustava myyjä voi käydä tietyn kaupunkijoukon kussakin kaupungissa täsmälleen kerran ja palata lopulta lähtökaupunkiin, eli minimoimaan kokonaismatkan tai Kustannukset, joita käytetään laajalti logistiikassa, tuotannon aikatauluissa ja muilla aloilla.

Määrittelemme ensin kaikki Kiinan provinssien pääkaupungit (mukaan lukienTaipei, Kiinan Taiwanin maakunnan pääkaupunki) ja sen koordinaattitiedot ja käyttö哈夫曼公式Laske kahden pisteen välinen etäisyys ja ohita sitten遗传算法Luo alkuperäinen populaatio, kopioi, mutatoi ja luo seuraava sukupolvi, optimoi polku jatkuvasti ja lopuksi tallenna lyhimmän polun etäisyys ja vastaava polku jokaisessa sukupolvessa, etsi lyhin polku kaikissa iteraatioissa ja näytä se visuaalisesti kartallaKaikki kaupunkipaikatKunto muuttuu iteraatioiden määrän mukaan Optimaalisen polun lisäksi lopputulos näyttää lyhimmän polun Chongqingista kaikkien kaupunkien läpi ja sen kokonaisetäisyyden. Harjoituksia suoritettiin yhteensä kaksi. Ensimmäinen iteraatioluku oli 2000 ja suoritusaika oli noin 3 minuuttia.

Yhteenvetona yhteen lauseeseen: alkaen Chongqingista, matkusta kaikkiin Kiinan provinssien pääkaupunkeihin ja käytä geneettisiä algoritmeja löytääksesi lyhimmän polun. Seuraava on koodin toteutus:

  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()

Kaikkien Kiinan provinssien pääkaupunkien sijainnin visualisointi:

kuva

Iteraatioiden määrä on 2000 (lyhin matka 31594 kilometriä):

Etsi historiallisen iterointiprosessin lyhimmän polun iteraatio ja visualisoi lyhin polku.

kuva

kuva

Tapaus 2: Iteraatioiden määrä on 20 000 (lyhin saatu matka on 29 768 kilometriä)

Etsi iteraatio, jolla on lyhin polku historiallisen iteraatioprosessin aikana, ja visualisoi lyhin polku tälle iteraatiolle.

kuva

kuva

Yllä oleva sisältö on tiivistetty Internetistä, jos siitä on apua, lähetä se eteenpäin.