) `" h: X& m) Z/ ?+ z$ w& `9 M3 Y. T5 s8 [9 g4 d1 y
当依据轮盘赌方式进行选择时,则概率越大的越容易被选择到。, ?: E6 n6 ~$ z$ S
6 w- n1 e) W6 A0 G i. b1 x3.4 交叉操作# B' a9 M) [7 p r: u* {& c" n
交叉操作也有许多种:单点交叉,两点交叉等。此处仅讲解一下两点交叉。首先利用选择操作从种群中选择两个父辈个体parent1和parent2,然后随机产生两个位置pos1和pos2,将这两个位置中间的基因位信息进行交换,便得到下图所示的off1和off2两个个体,但是这两个个体中一般会存在基因位信息冲突的现象(整数编码时),此时需要对off1和off2个体进行调整:off1中的冲突基因根据parent1中的基因调整为parent2中的相同位置处的基因。如off1中的“1”出现了两次,则第二处的“1”需要调整为parent1中“1”对应的parent2中的“4”,依次类推处理off1中的相冲突的基因。需要注意的是,调整off2,则需要参考parent2。1 X; y1 r8 {+ d' j- \9 I
4 o: ]/ ~" g3 t( ]
: ~- P1 @6 a, N. F- x! s0 {0 T 3 d( X6 h, @, i% s4、Python代码 : u0 n; ?- N _' m0 }9 l#-*- coding:utf-8 -*- # t. t/ `: Z, j( Y6 N) w2 m9 S + W' D# E1 c- h+ Qimport random - U0 I% E+ ^) H+ Pimport math / I( f% [1 w$ x1 E7 Xfrom operator import itemgetter . l ?+ r8 x4 b! R" ] / _1 s/ _% h9 L0 `class Gene:0 ^" b1 Z! I6 y3 S) P1 [: U6 Z( W- a
''' . M# @" Q4 y4 S5 q5 L( w This is a class to represent individual(Gene) in GA algorithom5 u) v& l$ K5 [. h: x1 c( x
each object of this class have two attribute: data, size* L- u$ T2 i$ e+ ~) v; y3 `
''' ( L# Q3 ^/ A! s6 N def __init__(self,**data):7 l8 d$ G- F+ B l' L) O/ X6 d
self.__dict__.update(data) # p( y9 C( x4 }" N, ^# P5 I self.size = len(data['data'])#length of gene 5 u! S: q' q. M5 f- a' g4 w 3 l# i% K! c8 Y5 h. P% W0 t! A0 T3 g1 f
class GA: $ ?$ k& ?" g R2 P" `$ z% { ''' & ^; a) i' S9 N, `5 f This is a class of GA algorithm. % N4 L3 R3 h8 h$ L
'''2 y7 j) v1 ~ E1 C
def __init__(self,parameter): ! C7 T5 Q0 a5 {7 @3 D/ T ''' * Z" M5 d9 A. }* r" A) Z& L Initialize the pop of GA algorithom and evaluate the pop by computing its' fitness value .' g Z3 g1 P& N: g. W
The data structure of pop is composed of several individuals which has the form like that:( {& `$ `; Q; N y J
2 R6 a. g1 T. i" F0 t% a
{'Gene':a object of class Gene, 'fitness': 1.02(for example)}) ^( x' F- {- j/ y4 S( l
Representation of Gene is a list: [b s0 u0 sita0 s1 u1 sita1 s2 u2 sita2]/ f: H6 z- \: T
, W, V. y/ z% r1 p- B* @
'''7 x# q5 [+ ]: _6 X2 y
#parameter = [CXPB, MUTPB, NGEN, popsize, low, up] 8 A& y3 \/ n9 B self.parameter = parameter " O7 K+ O* T( f; p. q8 j( k* d4 i7 h9 I& F7 [( _3 U
low = self.parameter[4] 8 V0 L! b1 ~' y% M1 T1 I up = self.parameter[5] & u1 [0 |# ~4 \4 d, y3 o7 T8 ? M
self.bound = []$ X a& ?9 [0 i, o% o" E
self.bound.append(low) . I1 P+ _+ b: @# u self.bound.append(up)! R: Q2 I3 F' V
8 T4 Z6 ?3 Y" q+ X9 M E pop = [] , p+ G7 A% c) Q3 h* n6 F5 U for i in range(self.parameter[3]):$ a8 L& |% |. d, T
geneinfo = [] " ^& I {, y: j+ v* u for pos in range(len(low)):: r* B w! R# ?5 t/ n3 i
geneinfo.append(random.uniform(self.bound[0][pos], self.bound[1][pos]))#initialise popluation5 p7 u7 e* N4 z1 F' ?
& `; g9 F- t5 g+ d- k2 A
fitness = evaluate(geneinfo)#evaluate each chromosome& P# I$ o/ k1 [
pop.append({'Gene':Gene(data = geneinfo), 'fitness':fitness})#store the chromosome and its fitness # X( ]* h7 T3 I9 q3 B3 B' Y2 r" i- A% z
self.pop = pop/ j- ]& ?4 C3 F8 A9 m
self.bestindividual = self.selectBest(self.pop)#store the best chromosome in the population ( L; L0 t- H* b# d) {; m( E" U* U% [7 Q4 |9 Z& j& M! Q. {% \
def selectBest(self, pop):, P( V- H, x% `& u9 ?; m
''' " I" }0 f) W+ Y! y6 n select the best individual from pop " x1 O$ {# S+ Y6 X: j" N/ h ''' 5 h1 S: v: U5 L- H. t8 Y/ C+ q: e s_inds = sorted(pop, key = itemgetter("fitness"), reverse = False) `& }) O6 S" ?2 R9 q return s_inds[0]# M" X8 @: [& v3 H# N3 ?. f
' c3 T- d' O' d# N5 X& [
def selection(self, individuals, k):0 ^ S0 w5 o4 N9 n J% h0 c
'''4 }1 q0 z2 P) i$ v
select two individuals from pop : j/ S6 q3 b) p9 g. p+ \ ''' o+ r. X! ~1 u( Z6 ] ^5 W s_inds = sorted(individuals, key = itemgetter("fitness"), reverse=True)#sort the pop by the reference of 1/fitness ) E; c+ G P' m7 a# }+ L# \ sum_fits = sum(1/ind['fitness'] for ind in individuals) #sum up the 1/fitness of the whole pop $ O& W9 L0 x" O& N- s* Q5 B' X/ i$ K0 i
chosen = [] ' W3 }5 P3 h! _. i4 u+ M for i in xrange(k): 5 u! v( E4 k; [4 d u = random.random() * sum_fits#randomly produce a num in the range of [0, sum_fits] 6 N5 _) Q' `$ |5 ~ sum_ = 0 0 y9 J0 ^! g6 T: X0 p0 A for ind in s_inds: * C5 [7 h9 O6 s0 y: S sum_ += 1/ind['fitness']#sum up the 1/fitness ; ~/ f9 K' o- c1 z8 O if sum_ > u:* C# K+ V9 u4 H1 J; M1 A% n; p
#when the sum of 1/fitness is bigger than u, choose the one, which means u is in the range of [sum(1,2,...,n-1),sum(1,2,...,n)] and is time to choose the one ,namely n-th individual in the pop: m5 ^9 E" `- ^: M& C2 M/ i
chosen.append(ind). g* D& n2 K4 K, d! Q# v" h
break * P- `/ w' j& i; v9 q, I/ g8 y: m, E5 Q/ @$ C
return chosen : B& H4 a k& _1 S/ d
5 m+ U- o; K( w" C. g; a
# t, D+ Y" {, D6 Q# }3 m6 i
def crossoperate(self, offspring): 3 c" G4 Z( j& W& @ ''' $ n, e. i4 \' R0 p- |% [ s cross operation5 T/ V, T7 S, d s0 N& a2 o
''' 8 K& b( e. D+ U4 D8 E3 d9 [, ~ dim = len(offspring[0]['Gene'].data) + J* z |6 B& o3 k4 a , P6 b9 ]2 I' i geninfo1 = offspring[0]['Gene'].data#Gene's data of first offspring chosen from the selected pop+ K' c9 Y4 d% l2 Z' S
geninfo2 = offspring[1]['Gene'].data#Gene's data of second offspring chosen from the selected pop. O, x; h$ H: A
. y, _: W- k/ i: i pos1 = random.randrange(1,dim)#select a position in the range from 0 to dim-1, 6 o: v+ F" a7 i c! w
pos2 = random.randrange(1,dim) - B& S( n" t& O, L r2 ? . O: i# L9 K5 z) {! m: X newoff = Gene(data = [])#offspring produced by cross operation 3 j3 V- b: R. h* b( O6 H! Y2 q' [ temp = []- A) o3 e. k- @$ Y" u; m
for i in range(dim):$ w2 _7 Q8 S: q8 a: o3 \0 M
if (i >= min(pos1,pos2) and i <= max(pos1,pos2)): $ R% Q6 l a- ^8 A6 O7 d! q temp.append(geninfo2) + j5 N! n" C. G$ S/ @- K #the gene data of offspring produced by cross operation is from the second offspring in the range [min(pos1,pos2),max(pos1,pos2)] * _3 z ^0 f- v+ X8 J& A else:4 V& T! ^% M, [0 |
temp.append(geninfo1)( M `# [& a9 j
#the gene data of offspring produced by cross operation is from the frist offspring in the range [min(pos1,pos2),max(pos1,pos2)] & N- N, @8 P6 V! f$ y& K& S% z newoff.data = temp" l1 w: E4 E# I
+ _) @; Y1 F: y* n/ Z* X; w6 E, F return newoff" Q5 U2 ~- ]8 J& ]; P* Z
% K$ W& j! l8 a. | l
# q' c- ~. |' z5 }& k4 j# |
def mutation(self, crossoff, bound): 0 X9 h1 g/ K+ z2 U ''' * S6 {5 |( r, H0 W4 f3 |# X5 i mutation operation " [, L: C6 Q4 O3 p+ `0 T9 }- N: v) ]* [6 D '''% u7 L3 L C7 E7 l: v9 i
, h% w% b: }- W
dim = len(crossoff.data) 0 Z4 s. p+ {0 Z) ]5 C # I3 n1 o/ w6 I R+ w' p3 n; J pos = random.randrange(1,dim)#chose a position in crossoff to perform mutation. - ^+ H0 p( c0 v$ T G. X1 p) y |7 S% @
crossoff.data[pos] = random.uniform(bound[0][pos],bound[1][pos]) 9 |2 C U9 m7 |$ B& J4 q) H3 v return crossoff2 M) r4 a; @; Z( G9 ~
/ a" f+ l9 Z' g' l7 p. m4 ]
def GA_main(self): $ U7 S* k5 i( s5 [" G '''* E1 {! q- k6 I! N, W! l
main frame work of GA : J' P ^5 B( C* L3 b! @% p: Y9 A ''') {( M }5 |5 e
0 ]5 c4 u z' }- J print("Start of evolution") 0 I2 B4 w& n2 I: H! V" I _ 9 j1 e" q* g9 i* l # Begin the evolution8 R' Z4 w* i' N$ p4 g* E) w) J
for g in range(NGEN): 8 l1 O- N+ ^9 Y% N2 e2 e 4 A/ A8 K0 z6 U5 _; w print("-- Generation %i --" % g) 3 |% L* R) [: d! L$ n M. u& X1 C
1 I* F% q! ~, r #Apply selection based on their converted fitness2 D0 e: h& x' Q8 f& y, \0 D
selectpop = self.selection(self.pop, popsize) 1 H* g, U0 \1 g. O0 |
( F4 ?: C( d- P, X, |6 g nextoff = [] " R; e9 \, S; b- Q5 V0 [' ]
while len(nextoff) != popsize: ' K# ~$ T X3 h h V& B+ F- W
# Apply crossover and mutation on the offspring , p, B/ R$ f5 w
7 ^6 L: _1 N+ W% a x
# Select two individuals 1 n2 n' N! @; v6 O1 a! {- W/ Q offspring = [random.choice(selectpop) for i in xrange(2)] / V+ w5 n: ?7 z) p* y5 M9 [/ O2 ^% S8 x+ y$ N. ?
if random.random() < CXPB: # cross two individuals with probability CXPB ' s8 T& B8 ~# i8 r, h crossoff = self.crossoperate(offspring) ( {4 I/ @: _; H8 G fit_crossoff = evaluate(self.xydata, crossoff.data)# Evaluate the individuals , Z7 d3 G0 I8 |' j5 ?
) x# ?3 r# Z2 | ~6 s- _
if random.random() < MUTPB: # mutate an individual with probability MUTPB , t% T+ h( J& |5 C" J muteoff = self.mutation(crossoff,self.bound) ' D" H. ^) h3 W fit_muteoff = evaluate(self.xydata, muteoff.data)# Evaluate the individuals . H+ Y3 Y% D, d9 ]0 t, I: C nextoff.append({'Gene':muteoff,'fitness':fit_muteoff})4 d- S, C% n1 q$ h
3 H( f8 E; C& b6 R # The population is entirely replaced by the offspring3 S7 A8 W) e. v8 Y, Q/ u9 Z# X5 u
self.pop = nextoff: r+ C( k d8 s. g1 {6 r
1 _# c+ b* k7 ^2 ?5 ^
# Gather all the fitnesses in one list and print the stats( N2 ~0 M- E5 c0 w
fits = [ind['fitness'] for ind in self.pop]+ ~! G7 O2 E- c' M' w, e
# T( [, F- W- a* O9 d Q
length = len(self.pop) ; p# }5 b% J$ P1 r* g mean = sum(fits) / length" A O) J, ^7 A' b4 o# s
sum2 = sum(x*x for x in fits)" v C1 |+ _/ ^9 I# J
std = abs(sum2 / length - mean**2)**0.5 3 I3 X) U( K' @( A, i' w2 B8 n best_ind = self.selectBest(self.pop)8 r9 p( \- t! E$ P6 n/ n
$ k% ~! Z: m4 M; d+ w; I( I+ O0 r
if best_ind['fitness'] < self.bestindividual['fitness']:# E" f2 G. _# v7 p, _8 t. v
self.bestindividual = best_ind7 K+ f% r/ r( \" O+ Z; I
8 v6 x/ J7 m' `$ h5 Y x6 N; D+ a
print("Best individual found is %s, %s" % (self.bestindividual['Gene'].data,self.bestindividual['fitness'])) 1 f5 f& G& z% t& I8 O print(" Min fitness of current pop: %s" % min(fits)) & u2 [% T& P; i% @0 | print(" Max fitness of current pop: %s" % max(fits)) : y2 N o- ~- `5 A print(" Avg fitness of current pop: %s" % mean)- Z6 Q4 p+ j( q& u. v; ~2 N* D
print(" Std of currrent pop: %s" % std) 1 I9 Z' D+ W: K/ i6 x( [ ( O4 O0 A5 Y& d& q% e print("-- End of (successful) evolution --") ; l( h3 r/ S- E9 }- _ ^
3 f4 Q% l; {" o* Q6 Bif __name__ == "__main__":3 A0 [/ e2 j, a+ u T6 O
. S# M5 R) X% x: N CXPB, MUTPB, NGEN, popsize = 0.8, 0.3, 50, 100#control parameters 3 D. w2 r& R$ R, U3 { - g2 E4 }' C8 k+ P6 N up = [64, 64, 64, 64, 64, 64, 64, 64, 64, 64]#upper range for variables* h- x0 C% n6 O8 b$ l
low = [-64, -64, -64, -64, -64, -64, -64, -64, -64, -64]#lower range for variables : h" w9 d/ U5 e# a9 x2 P0 s parameter = [CXPB, MUTPB, NGEN, popsize, low, up]9 T+ w" r' ^3 o$ i