用遗传算法找函数最大值!手把手教你Python实现(附完整代码)

该文章已生成可运行项目,

一、这个数学题居然用生物进化来解?

咱们先来看这个经典问题:y = x² 在区间[-10,10]找最大值。正常解法求导找极值点?那太没意思了!(拍桌)今天玩个大的——用遗传算法模拟生物进化来找答案!

遗传算法的神奇之处在于,它把数学问题转化成了生存游戏。想象一群数字生物在解空间里游荡,强的活下来繁衍后代,弱的被淘汰,经过N代进化后,最终找到最优解!

二、算法核心六步走(必考知识点)

  1. 种群初始化:随机生成20-100个初始解(别太少!)
  2. 二进制编码:把实数转成二进制,比如5→0101(注意编码长度影响精度)
  3. 适应度计算:每个解的y值就是它的分数,y越大越优秀
  4. 选择交配:轮盘赌选父母,概率=个体适应度/总适应度
  5. 染色体交叉:随机选交叉点交换基因片段(推荐单点交叉)
  6. 基因变异:按1%-5%概率翻转某个bit(变异率别太高!)

举个🌰:假设初始解是3(0011)和5(0101),交叉后可能变成0011和0101,变异可能变成0010

三、Python代码逐行解析

import random
import matplotlib.pyplot as plt

# 目标函数(这里可以替换成任何函数!)
def target_function(x):
    return x ** 2

# 二进制转十进制(注意精度调节)
def decode(binary, lower=-10, upper=10, bit_length=16):
    int_val = int(''.join(map(str,binary)),2)
    return lower + (upper - lower) * int_val / (2**bit_length -1)

# 生成随机个体
def create_individual(bit_length):
    return [random.randint(0,1) for _ in range(bit_length)]

# 交叉操作(这里使用单点交叉)
def crossover(parent1, parent2):
    point = random.randint(1,len(parent1)-2)
    return parent1[:point]+parent2[point:], parent2[:point]+parent1[point:]

# 变异操作(随机翻转一个bit)
def mutate(child):
    index = random.randint(0,len(child)-1)
    child[index] ^= 1
    return child

# 主程序
population_size = 50
generations = 100
bit_length = 16
mutation_rate = 0.01
history = []

# 初始化种群
population = [create_individual(bit_length) for _ in range(population_size)]

for _ in range(generations):
    # 计算适应度
    fitness = [target_function(decode(ind)) for ind in population]
    history.append(max(fitness))
    
    # 选择
    selected = random.choices(
        population,
        weights=fitness,
        k=population_size
    )
    
    # 交叉变异
    new_population = []
    for i in range(0, population_size, 2):
        parent1 = selected[i]
        parent2 = selected[i+1]
        child1, child2 = crossover(parent1, parent2)
        
        if random.random() < mutation_rate:
            child1 = mutate(child1)
        if random.random() < mutation_rate:
            child2 = mutate(child2)
            
        new_population.extend([child1, child2])
    
    population = new_population

# 可视化进化过程
plt.plot(history)
plt.title('进化轨迹(最大值变化曲线)')
plt.xlabel('Generation')
plt.ylabel('Max Value')
plt.show()

四、调参进阶技巧(血泪经验)

  • 种群数量:20-200之间,太大会降低效率,太小容易早熟
  • 变异率:0.5%-5%是黄金区间(超过10%就成随机搜索了!)
  • 编码长度:16位精度可达0.0003,32位精度更高但更耗内存
  • 精英保留:每代保留前5%最优个体不参与交叉变异(防退化)

五、常见坑点预警!!

  1. 早熟收敛:所有个体都一模一样?快检查变异率是不是太低了!
  2. 收敛过慢:尝试增大选择压力(比如用锦标赛选择代替轮盘赌)
  3. 精度不够:把二进制编码长度从16位提到32位试试
  4. 负数处理:记得在解码时转换数值范围(比如-10到10)

六、效果展示与扩展

运行代码后你会看到,算法在约30代时就找到了接近100的最大值(实际理论最大值是10²=100)。如果把目标函数改成其他复杂函数(比如sin(x)+cos(2x)),只需要修改target_function即可!

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

七、还能怎么玩更刺激?

  • 多峰值函数:试试y = x + 10sin(5x) +7cos(4x),看算法能否找到全部极值
  • 动态环境:让目标函数随时间变化,考验算法的实时追踪能力
  • 多目标优化:同时优化多个目标函数(需要引入Pareto最优解)

八、为什么选遗传算法?

比起梯度下降等传统方法,它有三大优势:

  1. 不需要目标函数可导(黑箱优化也OK!)
  2. 全局搜索能力强(不易陷入局部最优)
  3. 并行性好(种群中的个体可以同时进化)

下次遇到复杂优化问题,别急着求导,试试让计算机帮你"进化"出一个最优解吧!记得调参时多试几次,遗传算法有时候也看"运气"呢~(笑)

本文章已经生成可运行项目
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值