遗传算法求函数最大值:从数学公式到代码实现的奇妙旅程

(前排提示:本文包含大量手撕代码和灵魂画图,建议搭配瓜子阅读效果更佳~)

一、这个数学题不简单!

咱们先来看一个魔鬼函数:

f(x,y,z) = sin(x²+y²+z²) / (x²+y²+z² + 1e-6) + 0.1*(x+y+z)

这个三维函数的最大值在哪里?传统微积分方法可能当场去世——求导方程复杂到怀疑人生!(别问我怎么知道的,头发就是这么没的)

举个栗子🌰:假设我们要找这个函数在区间[-5,5]³范围内的最大值,常规网格搜索法需要:

  • 每个维度取100个点 → 总共100³=1,000,000次计算
  • 每次计算耗时0.1ms → 总耗时100秒!

(此时一位遗传算法选手优雅路过)

二、遗传算法的魔法原理

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

(示意图,具体步骤往下看↓↓↓)

核心六步走:

  1. 基因编码:把解空间映射到染色体(比如二进制编码)
  2. 种群初始化:随机生成N个个体
  3. 适应度评估:计算每个个体的函数值
  4. 选择操作:保留优秀个体(轮盘赌/锦标赛)
  5. 交叉变异:产生新个体(基因重组)
  6. 迭代进化:直到满足终止条件

举个接地气的例子:假设要找全中国最高的人

  • 编码:用GPS坐标表示位置
  • 种群:随机选100个城市
  • 适应度:量身高
  • 选择:重点在北方地区找
  • 变异:偶尔去南方找找惊喜

三、手把手写Python代码

import numpy as np

# 超参数设置(重点!!!)
POP_SIZE = 50       # 种群规模
DNA_SIZE = 24       # 每个维度8位二进制(3维×8=24)
CROSS_RATE = 0.8    # 交叉概率
MUTATION_RATE = 0.003
N_GENERATIONS = 200
X_BOUND = [-5, 5]   # 取值范围

# 目标函数(三维版)
def F(x, y, z):
    r = x**2 + y**2 + z**2
    return np.sin(r)/(r + 1e-6) + 0.1*(x+y+z)

# 解码器:二进制转实数
def translateDNA(pop):
    return pop.dot(2 ** np.arange(DNA_SIZE)[::-1]) / (2**DNA_SIZE-1) * \
           (X_BOUND[1]-X_BOUND[0]) + X_BOUND[0]

# 适应度计算(重要!!!)
def get_fitness(pred):
    return pred - np.min(pred) + 1e-6  # 确保非负

# 选择(轮盘赌法)
def select(pop, fitness):
    idx = np.random.choice(np.arange(POP_SIZE), size=POP_SIZE, 
                          replace=True, p=fitness/fitness.sum())
    return pop[idx]

# 交叉(单点交叉)
def crossover(parent, pop):
    if np.random.rand() < CROSS_RATE:
        i_ = np.random.randint(0, POP_SIZE, size=1)
        cross_points = np.random.randint(0, 2, DNA_SIZE).astype(np.bool)
        parent[cross_points] = pop[i_, cross_points]
    return parent

# 变异(位翻转)
def mutate(child):
    for point in range(DNA_SIZE):
        if np.random.rand() < MUTATION_RATE:
            child[point] = 1 if child[point]==0 else 0
    return child

# 主程序(开始表演!)
pop = np.random.randint(2, size=(POP_SIZE, DNA_SIZE)) 

for _ in range(N_GENERATIONS):
    # 解码三维坐标
    xyz = translateDNA(pop).reshape(-1,3)
    x, y, z = xyz[:,0], xyz[:,1], xyz[:,2]
    
    # 计算适应度
    F_values = F(x, y, z)
    fitness = get_fitness(F_values)
    
    # 进化操作
    pop = select(pop, fitness)
    pop_copy = pop.copy()
    for parent in pop:
        child = crossover(parent, pop_copy)
        child = mutate(child)
        parent[:] = child

# 输出最佳解
best_xyz = translateDNA(pop)[np.argmax(F_values)]
print(f"最大值坐标:{best_xyz}, 函数值:{F(*best_xyz)}")

四、调参侠的生存指南

(血泪经验总结!!!)

  1. 种群大小:20-100效果较好,太大算得慢,太小早熟
  2. 变异率:0.001-0.1之间,太高变随机搜索,太低没创新
  3. 编码长度:每个维度8-12位,精度够用就好
  4. 早停策略:连续10代最优解不变就停(防过度拟合)
  5. 混合策略:最后用梯度下降微调(hybrid算法更香)

五、真实世界的应用场景

  • 天线设计:华为用遗传算法优化5G天线形状
  • 游戏AI:星际争霸的兵种搭配优化
  • 物流调度:京东的快递路径规划
  • 金融投资:基金组合的收益风险平衡
  • 医疗诊断:癌症筛查的特征选择

六、说点掏心窝的话

遗传算法就像个聪明的懒汉——不需要知道问题的深层结构,只要定义好适应度函数,它就能在解空间里乱窜找最优解。虽然不一定每次都能找到全局最优,但在复杂非线性问题上表现惊艳!

不过要注意(敲黑板):

  • 适合解空间大的问题
  • 需要合理设置超参数
  • 计算成本可能较高
  • 对离散问题支持较好

下次遇到求极值头秃的时候,不妨试试这个"达尔文式"的优化方法~ 说不定会有意外惊喜!(毕竟连大自然都能演化出人类,找个函数最大值还不是小菜一碟?)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值