Python实现遗传算法:基于面向对象与字典管理的完整代码解析

小岛来信
小岛来信
发布时间:2026-10-13| 3人浏览过
原创

本文详细介绍使用Python实现遗传算法的核心代码结构。通过定义Chromosome类封装染色体与适应度,并利用字典管理种群个体,实现了直观的对象化编程。文章解析了Genetic与Fitness模块中的关键函数,包括初始化、交叉、变异及最优解查找逻辑,并提供了完整的迭代优化与可视化示例,帮助开发者快速掌握遗传算法的工程实现。

前言

在前面的文章中,我们已经梳理了遗传算法的基本流程,并使用MATLAB进行了实现。本文的目标读者是已经阅读过前述内容、了解遗传算法基本概念的人群,因此不再重复解释算法原理,而是直接聚焦于Python环境下的具体实现细节。

Python遗传算法主程序架构

核心设计思路是构建一个染色体类,该类包含两个关键属性:染色体数据chrom与适应度fitness。通过直接实例化该对象,我们可以将种群中的每个个体表示为一个独立的对象,从而简化数据结构。

#染色体的类
class Chrom:
  chrom = []
  fitness = 0
  def showChrom(self):
    print(self.chrom)
  def showFitness(self):
    print(self.fitness)

接下来设定基础参数。种群的存储方式采用字典结构,即利用一个字典来保存种群内的所有个体。这种设计是我探索出的创建和管理多个对象的有效方法。

在字典中,索引设置为个体的标识符(如chrom1、chrom2等),而索引对应的值则是具体的对象实例。每个对象实例包含两个属性:染色体数据和适应度值。

从设计思路上看,这种方法优于MATLAB的矩阵式编程。它直观地表达了“个体”与其“属性”之间的关系,相比处理复杂的矩阵运算,这种逻辑更易于理解和接受。

#基础参数
N = 200 #种群内个体数目
mut = 0.2 #突变概率
acr = 0.2 #交叉概率

pop = {} #存储染色体的字典
for i in range(N):
  pop['chrom'+str(i)] = Chrom()
chromNodes = 2 #染色体节点数(变量个数)
iterNum = 10000 #迭代次数
chromRange = [[0, 10], [0, 10]] #染色体范围
aveFitnessList = [] #平均适应度
bestFitnessList = [] #最优适应度

随后涉及染色体的初始化过程,这包括种群初始化、适应度计算以及最优解搜索等函数。为了代码清晰,我将这些功能拆分为两个文件:Genetic.py和Fitness.py。

Genetic.py文件中包含八个主要函数,负责种群操作或染色体层面的处理,具体包括:

  1. findBest函数:用于在种群中查找适应度最高的最优染色体;
  2. findWorse函数:用于在种群中查找适应度最低的最劣染色体;
  3. initialize函数:用于对种群进行初始化操作;
  4. calAveFitness函数:用于计算整个种群的平均适应度;
  5. mutChrom函数:用于对染色体执行变异操作;
  6. inRange函数:用于判断染色体节点的值是否超出预设范围;
  7. acrChrom函数:用于对染色体执行交叉操作;
  8. compareChrom函数:用于比较两个染色体的优劣。

Fitness.py文件中包含两个主要函数,专注于适应度的计算,具体包括:

  1. calFitness函数:用于遍历种群中的每个个体,并调用funcFitness函数计算其适应度;
  2. funcFitness函数:用于计算单个特定染色体的适应度值。

基于上述模块,初始化代码的逻辑如下:

#初始染色体
pop = Genetic.initialize(pop, chromNodes, chromRange)
pop = Fitness.calFitness(pop) #计算适应度
bestChrom = Genetic.findBest(pop) #寻找最优染色体
bestFitnessList.append(bestChrom[1]) #将当前最优适应度压入列表中
aveFitnessList.append(Genetic.calAveFitness(pop, N)) #计算并存储平均适应度

迭代过程的思路与逻辑与MATLAB实现基本一致。

#开始迭代
for t in range(iterNum):
  #染色体突变
  pop = Genetic.mutChrom(pop, mut, chromNodes, bestChrom, chromRange)
  #染色体交换
  pop = Genetic.acrChrom(pop, acr, chromNodes)
  #寻找最优
  nowBestChrom = Genetic.findBest(pop)
  #比较前一个时间的最优和现在的最优
  bestChrom = Genetic.compareChrom(nowBestChrom, bestChrom)
  #寻找与替换最劣
  worseChrom = Genetic.findWorse(pop)
  pop[worseChrom[0]].chrom = pop[bestChrom[0]].chrom.copy()
  pop[worseChrom[0]].fitness = pop[bestChrom[0]].fitness
  #存储最优与平均
  bestFitnessList.append(bestChrom[1])
  aveFitnessList.append(Genetic.calAveFitness(pop, N))

最后,我们需要绘制迭代过程的图像以观察收敛情况。

plt.figure(1)
plt.plot(x, aveFitnessList)
plt.plot(x, bestFitnessList)
plt.show()

在代码最前端引入所需的库文件和模块后,即可运行整个程序。

import Genetic
import Fitness
import matplotlib.pyplot as plt
import numpy as np

开发心得

主要的感悟在于染色体类的封装。虽然Genetic.py和Fitness.py中的函数也可以包装成类,但这会导致主文件过于臃肿,且在外部再次封装显得多余。鉴于这是一个小型程序,当前的写法更为简洁。

深刻体会到面向对象编程的优势。在逻辑处理上,只需关注对象的属性,省去了许多底层细节的复杂思考,编程体验更加顺畅。

另一个感悟是关于创建多个对象的方法。起初我困惑于如何在Python中实现类似C++的对象数组,经过搜索和尝试,最终找到了利用字典索引来管理对象的方法。

关于这一方法的具体细节,后续有机会再详细展开,本文暂告一段落。

补充剩余函数的实现细节

首先是Genetic.py中八个函数的具体实现:

import random

#寻找最优染色体
def findBest(pop):
  best = ['1', 0.0000001]
  for i in pop:
    if best[1] < pop[i].fitness:
      best = [i, pop[i].fitness]
  return best

#寻找最劣染色体
def findWorse(pop):
  worse = ['1', 999999]
  for i in pop:
    if worse[1] > pop[i].fitness:
      worse = [i, pop[i].fitness]
  return worse

#赋初始值
def initialize(pop, chromNodes, chromRange):
  for i in pop:
    chromList = []
    for j in range(chromNodes):
      chromList.append(random.uniform(chromRange[j][0], chromRange[j][1]+1))
    pop[i].chrom = chromList.copy()
  return pop

#计算平均适应度
def calAveFitness(pop, N):
  sumFitness = 0
  for i in pop:
    sumFitness = sumFitness + pop[i].fitness
  aveFitness = sumFitness / N
  return aveFitness

#进行突变
def mutChrom(pop, mut, chromNodes, bestChrom, chromRange):
  for i in pop:
    #如果随机数小于变异概率(即可以变异)
    if mut > random.random():
      mutNode = random.randrange(0,chromNodes)
      mutRange = random.random() * (1-pop[i].fitness/bestChrom[1])**2
      pop[i].chrom[mutNode] = pop[i].chrom[mutNode] * (1+mutRange)
      #判断变异后的范围是否在要求范围内
      pop[i].chrom[mutNode] = inRange(pop[i].chrom[mutNode], chromRange[mutNode])
  return pop

#检验便宜范围是否在要求范围内
def inRange(mutNode, chromRange):
  if chromRange[0] < mutNode < chromRange[1]:
    return mutNode
  elif mutNode-chromRange[0] > mutNode-chromRange[1]:
    return chromRange[1]
  else:
    return chromRange[0]

#进行交叉
def acrChrom(pop, acr, chromNodes):
  for i in pop:
    for j in pop:
      if acr > random.random():
        acrNode = random.randrange(0, chromNodes)
        #两个染色体节点进行交换
        pop[i].chrom[acrNode], pop[j].chrom[acrNode] = pop[j].chrom[acrNode], pop[i].chrom[acrNode]
  return pop

#进行比较
def compareChrom(nowbestChrom, bestChrom):
  if bestChrom[1] > nowbestChrom[1]:
    return bestChrom
  else:
    return nowbestChrom

接着是Fitness.py中两个函数的具体实现:

import math

def calFitness(pop):
  
  for i in pop:
    #计算每个染色体的适应度
    pop[i].fitness = funcFitness(pop[i].chrom)

  return pop

def funcFitness(chrom):
  #适应度函数
  fitness = math.sin(chrom[0])+math.cos(chrom[1])+0.1*(chrom[0]+chrom[1])

以上就是本文的全部内容,希望对各位的学习有所帮助,也欢迎大家继续支持本站。

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。