写在前面
之前的文章中已经讲过了遗传算法的基本流程,并且用MATLAB实现过一遍了。这一篇文章主要面对的人群是看过了我之前的文章,因此我就不再赘述遗传算法是什么以及基本的内容了,假设大家已经知道我是怎么写遗传算法的了。
Python的遗传算法主函数
我的思想是,创建一个染色体的类,其中包括了两个变量:染色体chrom与适应度fitness。因此我们就可以通过直接建立对象来作为种群中的个体。
1
2
3
4
5
6
7
8
|
#染色体的类
class Chrom:
chrom = []
fitness = 0
def showChrom( self ):
print ( self .chrom)
def showFitness( self ):
print ( self .fitness)
|
所以我们开始设置基础参数。其中种群的表达方式我用的是字典,也就是用一个字典来保存种群内的所有个体,这个也是我想出来的创建多个对象的方法。
将字典的索引为个体的标号,如:chrom1, chrom2等。字典索引的值就是一个对象。这个对象拥有两个属性,就是染色体与适应度。
其实在这一方便来说,我觉得在思路上是优于利用MATLAB的矩阵式编程的。因为这样可以很直观的将个体与个体的属性这一种思想给表达出来,相比一堆矩阵来说,在逻辑上比较容易接受。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
#基础参数
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里面有八个函数,主要包含了作用于种群或者染色体操作的函数,分别为:
- findBest函数,用于寻找种群中的最优染色体;
- findworse函数,用于寻找种群中的最劣染色体;
- initialize函数,用于初始化种群;
- calAveFitness函数,用于计算种群的平均适应度;
- mutChrom函数,用于对染色体进行变异;
- inRange函数,用于判断染色体节点值是否越界;
- acrChrom函数,用于对染色体进行交叉;
- compareChrom函数,用于比较两个染色体孰优孰劣。
Fitness.py里面有两个函数,主要包含了对适应度操作的函数,分别为:
- calFitness函数,用来迭代每一个个体,并计算适应度(利用funcFitness函数计算);
- funcFitness函数,计算单个个体的适应度。
因此可以列出初始化代码为
1
2
3
4
5
6
|
#初始染色体
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无异
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
#开始迭代
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))
|
最后再做一下迭代的的图像
1
2
3
4
|
plt.figure( 1 )
plt.plot(x, aveFitnessList)
plt.plot(x, bestFitnessList)
plt.show()
|
最后再在最前面加上各种库和文件就可以运行了。
1
2
3
4
|
import Genetic
import Fitness
import matplotlib.pyplot as plt
import numpy as np
|
感悟
可以说最主要的感悟就是染色体这一个类。其实那个Genetic.py与Fitness.py这两个文件也可以直接包装成类,但是这样一来我就嫌主文件太臃肿,在其他里面再包装成类又多此一举,毕竟这只是一个小程序,所以我就这样写了。
深刻感悟到了面向对象编程的优点,在编程逻辑的处理上真是一种享受,只需要思考对象的属性即可,省去了许多复杂的思考。
另一个感悟就是创建多个对象时,利用字典的方法来创建对象。当初我也是困惑怎么建立一个类似于C++中的对象数组,上网查找了各种方法,结果都避而不谈(当然,也可能是我搜索能力太差没找到),所以经过尝试中遇到到了这种方法。
等有空我再详细说一下这个方法吧,这一次就先到这里。
剩余的函数补充
首先是Genetic.py里面的八个函数
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
|
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的两个函数
1
2
3
4
5
6
7
8
9
10
11
12
13
|
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 ])
|
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。
原文链接:http://www.jianshu.com/p/b049c68ef3c3?utm_source=tuicool&utm_medium=referral