python遗传算法_Python:遗传算法实现

关于遗传算法

遗传算法是仿照自然界中生物进化而产生的一类优化算法。个人感觉遗传算法简单粗暴,适应性广。关于遗传算法的介绍网上有很多了,这里按照我自己的理解简单概括一下。

编码解码,将待优化的参数编码为DNA序列,最简单直接的为二进制编码(即有两种碱基的DNA链);

生成随机初代

选择,适应度(由待优化的模型得到)较好的个体有更大的概率被选择,应用比较多的方法有轮盘赌和锦标赛;

按照一定概率进行随机的交叉变异

GOTO Step 2

经过多个世代的迭代之后,将会收敛到最优解。交叉和编译的作用是产生新个体,避免陷入局部最优解。

利用Python实现

前辈们常说一句话“避免重复造轮子”,其实最直接的还是搜一下别人写的包。这里之所以花时间自己搞一个主要是因为这个算法比较简单,逻辑性很明确,比较适合练手,因此才决定自己实现一下,算是敲开Python大门的第一个项目。

编码解码

这里选择使用二进制编码的方式来实现,根据用户输入的参数范围和精度计算出每个参数需要的位数,然后将参数空间均分映射为二进制编码。

Copy

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

# Encode parameters into DNA

def encode(self, parameters):

dna = ''

for i in range(self.nGenes):

geneSequenceDigit = (parameters[i]-self.parametersRange[i,0])/(self.parametersRange[i,1]-self.parametersRange[i,0])*(2**self.geneLength[i]-1)

geneSequenceDigit = int(round(geneSequenceDigit))

geneSequenceBin = self.int2bin(geneSequenceDigit, self.geneLength[i])

dna = dna + geneSequenceBin

dna = list(dna) # Trun string to list

return dna

# Decode DNA to parameters

def decode(self, dna):

dna = ''.join(dna) # Trun list to string

parameters = []

for i in range(self.nGenes):

geneSequenceBin = dna[self.dnaIdx[i,0]:self.dnaIdx[i,1]+1]

geneSequenceDigit = self.bin2int(geneSequenceBin)

parameterI = geneSequenceDigit/(2**self.geneLength[i]-1)*(self.parametersRange[i,1]-self.parametersRange[i,0])+self.parametersRange[i,0]

parameters.append(parameterI)

return parameters

# Returns the binary string of integer n, using count number of digits

def int2bin(self, n, count=32):

binStr = "".join([str((n >> y) & 1) for y in range(count-1, -1, -1)])

return binStr

# Returns digit integer of binary string

def bin2int(self, n):

ret = int(n,2)

return ret

这种方式实现的精度并不是确切的为用户输入的精度,而是要高于用户的输入精度。

选择

选择的策略使用了名为锦标赛的方式,同时添加了精英保留机制。锦标赛是指随机选择N个(通常N=2)候选个体,再从中选择最优的个体进入下一代,重复多次,直到子代规模达到要求。精英保留机制是是指保护已经产生的最优个体不被淘汰,不被交叉和变异破坏。

Copy

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

# Select individuals

def select(self):

nCandidates = 2

generation = []

for i in range(self.popGeneration):

candidates = random.choices(self.generation, k=nCandidates)

fitnessList = self.fitness(candidates=candidates)

bestFitness = max(fitnessList)

idx = fitnessList.index(bestFitness)

generation.append(candidates[idx].copy())

self.generation = generation

return

# Elitist preservation

def elitistPreservation(self):

bestFitness = max(self.fitnessList)

if bestFitness > self.bestFitness:

idx = self.fitnessList.index(bestFitness)

self.bestFitness = bestFitness

self.bestIndividual = self.generation[idx].copy()

else:

worstIndividual = min(self.fitnessList)

idx = self.fitnessList.index(worstIndividual)

self.generation[idx] = self.bestIndividual.copy()

self.fitnessList[idx] = self.bestFitness

return

交叉和变异

交叉和编译比较简单,利用随机数的方式来控制发生的概率。这里值得一提的是,现实中可能会发生多点的变异或者交叉,只不过概率非常低,在遗传算法的实现中如果仅仅采用单点的交叉和变异也是可以的。

代码和例子

使用例程:

Copy

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

import GeneticAlgorithm as GA # 导入GeneticAlgorithm模块

import math

# 根据具体的优化目标设计适应度函数,par为输入参数的列表,ret为适应度

def fitness(par):

x = par[0]

ret = x*math.sin(10*math.pi*x)+2

return ret

maxGen = 500 # 迭代次数

popGeneration = 50 # 每个世代的个体数目

pCross = 0.1 # 发生交叉的概率

pMutation = 0.05 # 发生变异的概率

nGenes = 1 # 待优化的参数的个数

parametersRange = [[-1, 2, 0.01]] # 待优化参数的范围及要求的精度,多个参数写法:[[-1, 2, 0.01],[-2, 3, 0.1]]

# 创建GA对象

ga = GA.GeneticAlgorithm(maxGen, popGeneration, pCross, pMutation, nGenes, parametersRange, fitness)

# 显示对象信息

ga.info()

# 执行优化

ga.run()

# 显示最优解

ga.result()

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值