遗传算法:如何用“进化”解决复杂问题?

发布于 2025-6-11 07:29
浏览
0收藏

你有没有想过,大自然是怎么让生物变得越来越强大的?

比如,为什么长颈鹿的脖子越来越长,为什么鸟儿的翅膀能飞得越来越远??

遗传算法:如何用“进化”解决复杂问题?-AI.x社区图片

其实,大自然有一套神奇的“优化”方法,而科学家们把这个方法用到了计算机里,这就是“遗传算法”。


接下来,我们将深入探讨遗传算法的设计思想、基本原理和实践应用,帮助你更好地理解和应用这一强大的优化工具。

1.前言|什么是遗传算法?

遗传算法(Genetic Algorithm,简称GA)起源于对生物系统的计算机模拟研究,是一种随机全局搜索优化方法。

它模拟了生物进化过程中的选择、交叉和变异等现象,从初始种群出发,通过一系列操作,使群体逐渐进化到搜索空间中更优的区域,最终收敛到一群最适应环境的个体,从而求得问题的优质解。

遗传算法:如何用“进化”解决复杂问题?-AI.x社区图片

▲ 遗传算法原理示意图

简单来说,它就像大自然一样,通过“选择”“交配”“变异”来找到解决问题的最好方法。

其中一些关键术语如下:

🔻种群(Population) 参与演化的生物群体,即解的搜索空间

  🔹染色体(Chromosome) 对应问题的解向量

▪️ 基因(Gene) 解向量的一个分量,或者编码后的解向量的一位

▪️ 个体(Individual) 种群的每一个成员,对应每一个可能的解

  🔹适应度(Fitness) 体现个体的生存能力,与目标函数相关的函数

🔻遗传算子(Operator) 个体的演化操作,包括选择、交叉、变异

  🔹选择(Selection) 基于适应度的优胜劣汰,以一定的概率从种群中选择若干个体

  🔹交叉(Crossover) 两个染色体进行基因重组

  🔹变异(Mutation):单个染色体的基因以较低概率发生随机变化

2.原理|遗传算法是怎么工作的?

遗传算法就像是在玩一个“寻宝游戏”。一开始,我们有很多“寻宝者”(这些“寻宝者”就是算法中的“种群”),它们都在不同的地方寻找宝藏(也就是问题的最优解)。

遗传算法:如何用“进化”解决复杂问题?-AI.x社区图片

▲ 藏宝图

每个“寻宝者”都有自己的“地图”(这个“地图”就是“基因”,它决定了“寻宝者”的特征和能力)。

遗传算法也是这样工作的。

初始种群产生了一系列随机解,选择操作保证了搜索的方向性,交叉和变异拓宽了搜索空间,其中交叉操作延续父辈个体的优良基因,变异操作则可能产生比当前优势基因更优秀的个体。

遗传算法:如何用“进化”解决复杂问题?-AI.x社区图片

▲ 人类进化演变图

变异操作有利于跳出局部最优解,同时增加了随机搜索的概率,即容易发散。因此,遗传算法需要在过早收敛(早熟)和发散、精度和效率之间平衡。

遗传算法的核心在于其模拟生物进化过程的几个关键操作:

选择操作|Selection

根据个体的适应度,以一定的概率从种群中选择若干个个体作为下一代的父母。

适应度高的个体有更高的被选中概率,这类似于自然选择中的“适者生存”

遗传算法会挑出那些“表现好”的个体,让它们有更多的机会繁殖后代。

常见方法:

  • 轮盘赌选择(Roulette Wheel Selection)根据个体的适应度值分配一个概率区间,适应度高的个体获得更大的区间。通过随机选择,适应度高的个体被选中的概率更高。
  • 锦标赛选择(Tournament Selection)随机选择若干个体进行“比赛”,适应度最高的个体获胜并进入下一代。
  • 排名选择(Rank Selection)根据个体的适应度进行排名,排名靠前的个体有更高的选择概率。这种方法适用于适应度值差异较大的情况。

交叉操作|Crossover

两个父本个体的基因在某一位置处被切断,前后两串分别交叉组合,形成两个新的子代个体。这一过程类似于生物的有性繁殖,通过基因重组产生新的变异。

遗传算法:如何用“进化”解决复杂问题?-AI.x社区图片

▲ 基因交叉组合

两个“表现好”的个体组合起来,产生新的后代。这个过程就像是生物的有性繁殖,新的后代会继承父母的优点。

常见方法:

  • 单点交叉(Single-point Crossover)在两个父代个体的染色体上随机选择一个交叉点,将交叉点之后的部分基因片段进行交换。
  • 多点交叉(Multi-point Crossover)选择多个交叉点进行基因片段的交换。
  • 均匀交叉(Uniform Crossover)随机决定每个基因位是否交换,使得基因片段的交换更加均匀。

变异操作|Mutation

对个体的基因序列进行随机变异,以一定的概率改变某个基因的值。这为种群引入了新的遗传信息,增加了种群的多样性,避免算法陷入局部最优。

偶尔,一些后代会发生随机的变化,这就像生物的基因突变。虽然大多数变异可能没什么用,但偶尔会有一些变异让后代变得更强大。

常见方法:

  • 位变异(Bit-flip Mutation)随机选择一个基因位,将其值从0变为1或从1变为0(适用于二进制编码)。
  • 均匀变异(Uniform Mutation)随机选择多个基因位进行变异。
  • 高斯变异(Gaussian Mutation)对基因值进行高斯分布的随机扰动(适用于实数编码)。

3.应用|遗传算法有什么用?

遗传算法在优化问题机器学习工程设计等领域有广泛应用,

例如在资源分配、路径规划、调度问题、特征选择、神经网络训练、超参数优化、结构设计、电路设计和系统优化等方面能够快速找到接近最优的解。

遗传算法:如何用“进化”解决复杂问题?-AI.x社区图片

▲ 梯度下降算法

其优势在于全局搜索能力强,可有效避免局部最优;适应性强,适用于非线性、高维度和多峰问题;并行性高,适合并行计算。

旅行推销员问题(TSP)是遗传算法的经典应用之一。

TSP问题要求从n个城市中找到一条最短路径,使推销员从某城市出发,唯一走遍所有城市后回到起点。

以下是一个用遗传算法解决TSP问题的Python示例。

import numpy as np
import matplotlib.pyplot as plt
import random
from math import sqrt
from matplotlib.collections import LineCollection


plt.rcParams['font.family'] = ['serif'] # 显示中文问题
plt.rcParams['font.serif'] = ['SimSun'] # 显示中文问题


# 生成随机城市坐标
def generate_cities(num_cities, width=1000, height=1000):
    return [(random.randint(0, width), random.randint(0, height)) for _ in range(num_cities)]


# 计算路径总距离
def calculate_distance(path, cities):
    distance = 0
    for i in range(len(path)):
        x1, y1 = cities[path[i-1]]
        x2, y2 = cities[path[i]]
        distance += sqrt((x2 - x1)**2 + (y2 - y1)**2)
    return distance


# 初始化种群
def initialize_population(pop_size, num_cities):
    population = []
    for _ in range(pop_size):
        individual = list(range(num_cities))
        random.shuffle(individual)
        population.append(individual)
    return population


# 选择操作 - 轮盘赌选择
def selection(population, cities, num_parents):
    fitness_values = [1/calculate_distance(individual, cities) for individual in population]
    total_fitness = sum(fitness_values)
    probabilities = [f/total_fitness for f in fitness_values]
    
    selected_indices = np.random.choice(len(population), size=num_parents, p=probabilities, replace=False)
    return [population[i] for i in selected_indices]


# 交叉操作 - 有序交叉(OX)
def crossover(parent1, parent2):
    size = len(parent1)
    child = [-1] * size
    
    # 选择交叉点
    start, end = sorted(random.sample(range(size), 2))
    
    # 从parent1复制片段
    child[start:end] = parent1[start:end]
    
    # 从parent2填充剩余城市
    remaining = [city for city in parent2 if city not in child]
    ptr = 0
    for i in range(size):
        if child[i] == -1:
            child[i] = remaining[ptr]
            ptr += 1
    
    return child


# 变异操作 - 交换变异
def mutate(individual, mutation_rate):
    if random.random() < mutation_rate:
        i, j = random.sample(range(len(individual)), 2)
        individual[i], individual[j] = individual[j], individual[i]
    return individual


# 遗传算法主函数
def genetic_algorithm(cities, pop_size=100, num_generatinotallow=500, mutation_rate=0.01, elitism_ratio=0.1):
    num_cities = len(cities)
    population = initialize_population(pop_size, num_cities)
    best_distance = float('inf')
    best_path = None
    fitness_history = []
    
    num_elites = int(pop_size * elitism_ratio)
    
    for generation in range(num_generations):
        # 评估种群
        distances = [calculate_distance(individual, cities) for individual in population]
        current_best = min(distances)
        fitness_history.append(current_best)
        
        if current_best < best_distance:
            best_distance = current_best
            best_path = population[distances.index(current_best)]
        
        # 选择精英
        elite_indices = np.argsort(distances)[:num_elites]
        elites = [population[i] for i in elite_indices]
        
        # 选择父母
        parents = selection(population, cities, pop_size - num_elites)
        
        # 生成下一代
        next_generation = elites.copy()
        
        while len(next_generation) < pop_size:
            parent1, parent2 = random.sample(parents, 2)
            child = crossover(parent1, parent2)
            child = mutate(child, mutation_rate)
            next_generation.append(child)
        
        population = next_generation
    
    return best_path, best_distance, fitness_history


# 绘制路径
def plot_path(cities, path, title="TSP Path"):
    path_coords = [cities[i] for i in path] + [cities[path[0]]]  # 回到起点
    x, y = zip(*path_coords)
    
    fig, ax = plt.subplots(figsize=(10, 6))
    ax.scatter(x, y, color='red')
    
    # 绘制路径线
    lines = [[path_coords[i], path_coords[i+1]] for i in range(len(path_coords)-1)]
    lc = LineCollection(lines, colors='blue', linewidths=1)
    ax.add_collection(lc)
    
    ax.set_title(title)
    ax.set_xlabel("X 轴")
    ax.set_ylabel("Y 轴")
    plt.grid()
    plt.show()


# 绘制适应度进化曲线
def plot_fitness_history(fitness_history, title="适应度进化曲线"):
    plt.figure(figsize=(10, 6))
    plt.plot(fitness_history, color='green')
    plt.title(title)
    plt.xlabel("迭代次数")
    plt.ylabel("最优距离")
    plt.grid()
    plt.show()


# 主程序
if __name__ == "__main__":
    # 参数设置
    num_cities = 20
    pop_size = 100
    num_generations = 500
    mutation_rate = 0.02
    
    # 生成城市
    cities = generate_cities(num_cities)
    
    # 运行遗传算法
    best_path, best_distance, fitness_history = genetic_algorithm(
        cities, pop_size=pop_size, num_generatinotallow=num_generations, mutation_rate=mutation_rate)
    
    print(f"最优距离: {best_distance}")
    print(f"最优路径: {best_path}")
    
    # 绘制结果
    plot_path(cities, best_path, f"旅行推销员问题(TSP) (最优距离: {best_distance:.2f})")
    plot_fitness_history(fitness_history)

遗传算法:如何用“进化”解决复杂问题?-AI.x社区图片


遗传算法:如何用“进化”解决复杂问题?-AI.x社区图片

▲ 程序输出结果

这个实现提供了TSP问题的基本遗传算法解决方案,可以作为进一步优化的基础。

 结语 

遗传算法虽然听起来很复杂,但其实它的核心思想非常简单:通过模拟自然选择的力量,逐步找到问题的最优解。它不仅是一种优化算法,更是一种从自然中汲取智慧的创新方法。

它让我们看到了自然选择的力量,也让我们相信,通过模仿自然,我们可以找到解决复杂问题的钥匙。

本文转载自Fairy Girl,作者:Fairy Girl

已于2025-6-11 09:42:04修改
收藏
回复
举报
回复
相关推荐