관리 메뉴

멍개의 연구소

유전 알고리즘 본문

컴퓨터 공학(Computer Science & Engineering))/알고리즘

유전 알고리즘

멍개. 2017. 4. 29. 21:23

간단하게 유전알고리즘을 구현을 해보자.


최종 유전자는 111111이다.


랜덤으로 30개의 유전자를 생성을 하여 111111에 가장 가까운 유전자 2개를 남기고 모두 지운다.


gene.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Genes():
    def __init__(self, status):
        self.status = status
        self.similar = 0
        self.what_similar()
 
 
    def what_similar(self):
        '''
            111111 6자리
        '''
        for i in str(self.status):
            if i == '1':
                self.similar += 1
 
    def __del__(self):
        print(self.status, '사망')
cs

해당 유전가자 111111에 얼마나 비슷한지 


echo.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
from gene import Genes as G
from random import random
 
class Ecosystem:
    def __init__(self, ge):
        self.generation = ge
        self.gene_list = self.initialize_gene()
        self.parents = []
        self.who_parents()
        self.none_parents_delete()
 
 
    #유전자 생성
    def initialize_gene(self):
        gene_list = []
        for i in range(30):
            while True:
                temp = int(random()*1000000)
                if len(str(temp)) == 6:
                    g = G(temp)
                    gene_list.append(g)
                    break
 
        return gene_list
 
 
    #부모 유전자 선택
    def who_parents(self):
        for i in range(2):
            temp = G(0)
            for j in range(30):
                if temp.similar < self.gene_list[j].similar and not self.gene_list[j] in self.parents :
                    temp = self.gene_list[j]
 
            self.parents.append(temp)
 
 
    #부모 유전자를 제외하고 제거
    def none_parents_delete(self):
        for index, item in enumerate(self.gene_list):
            del item
            self.gene_list[index] = None
        self.gene_list = []
 
 
cs



g.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from random import random
from echo import Ecosystem as Echo
 
 
 
if __name__ == "__main__":
    print(0'번째')
    echo = Echo(0)
    for i in echo.gene_list:
        if i is not None:
            print(i.status, i.similar)
 
    print('0세대 상위 유전자')
    print(echo.parents[0].status, echo.parents[0].similar)
    print(echo.parents[1].status, echo.parents[1].similar)
    print('=========================================')
cs


$ python g.py
0 번째
0 사망
0 사망
829402 사망
597979 사망
434582 사망
754965 사망
350844 사망
943519 사망
255545 사망
695438 사망
775939 사망
868224 사망
180944 사망
733226 사망
394287 사망
326435 사망
131053 사망
800439 사망
502259 사망
898596 사망
458853 사망
215984 사망
814521 사망
774371 사망
533304 사망
585691 사망
855598 사망
425682 사망
305393 사망
524938 사망
0세대 상위 유전자
182981 2
115467 2


30개의 유전자중 가장 강한 유전자 2개만 남겨두고 모두 죽었다. 이제 교차와 변이를 통해서 다시 유전자를 생성을 해보자.



echo.py를 다음 세대로 넘어가는 부분을 추가해보자 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#다음 세대
    def next_generation(self):
        self.match()
        self.who_parents()
        self.none_parents_delete()
 
 
    #상위 유전자 교배
    def match(self):
        temp = ''
        for o in range(30):
            for i in range(6):
                r =random()
                if r > 0.5 :
                    temp += str(self.parents[0].status)[i]
                else:
                    temp += str(self.parents[1].status)[i]
            g = G(int(temp))
            # print(temp)
            temp = ''
            self.gene_list.append(g)
            print(g.status, g.similar)
cs


0.5의 확률로 첫번째 부모 유전자나 두번째 부모의 유전자를 물려 받아서 유전자를 30개를 또다시 생성을 한후 이 중에서 다시 상위 유전자를 선택을 한다.


p.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from random import random
from echo import Ecosystem as Echo
 
if __name__ == "__main__":
    echo = Echo(0)
 
    for i in range(3):
        print(str(echo.generation) +'세대 유전자들')
        print(echo.parents[0].status, echo.parents[0].similar)
        print(echo.parents[1].status, echo.parents[1].similar)
        echo.next_generation()
 
        print(str(echo.generation) +'세대 유전자')
        for i in echo.parents:
            print(i.status, i.similar)
cs


$ python g.py
...중략...
111604 3
111604 3
1세대 상위 유전자
111604 3
111604 3
2세대 유전자들
111604 3
111604 3
111604 3
111604 3
111604 3
111604 3
111604 3
111604 3
111604 3
111604 3
111604 3
111604 3
111604 3
111604 3
111604 3
111604 3
111604 3
111604 3
111604 3
111604 3
111604 3
111604 3
111604 3
111604 3
111604 3
111604 3
111604 3
111604 3
111604 3
111604 3
111604 3
111604 3
2세대 상위 유전자
111604 3
111604 3
...

어느 순간부터 상위 유전자가 일치해진다 

해결 방법은 유전자 교차를 할 때 일정 확률로 유전자 변이를 일으키면 된다.

(근데 숫자 자릿수가 짧아서 그런지 몇세대 안돌아도 금방 된느듯 하네 ㅋㅋ)




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#상위 유전자 교배
    def match(self):
        temp = ''
        for o in range(30):
            for i in range(6):
                r =random()
                mutation_rate = random()
                if mutation_rate < 0.2 :
                    print(int(mutation_rate * 100)%10)
                    temp += str(int(mutation_rate * 100)%10)
                else :
                    if r > 0.5 :
                        temp += str(self.parents[0].status)[i]
                    else:
                        temp += str(self.parents[1].status)[i]
            g = G(int(temp))
            # print(temp)
            temp = ''
            self.gene_list.append(g)
            print(g.status, g.similar)
cs


match 부분을 살짝 수정을 하여 0.2의 확률로 변이를 일으켰다.


변이가 정상적으로 작동하는지 테스트를 위해 높은 확률을 주었다.


$ python g.py
...중략...
118110 4
111111 6
2세대 상위 유전
111111 6
111111 6

결과가 나온다.


이제 마지막으로 모든 유전자가 111111인지 확인하는 부분을 추가해주자.


echo.py



중간 중간 수정을 한 부분이 있다.


g.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from random import random
from echo import Ecosystem as Echo
import time
 
if __name__ == "__main__":
    option1 = {
                "gene_count" : 30,
                "gene_length" : 6,
                "mutation_probability" : 0.1
            }
    echo = Echo(option1)
 
    while echo.is_continue():
        print('=======================')
        print(str(echo.generation) +'세대 유전자들')
        echo.next_generation()
 
        print(str(echo.generation - 1+'세대 상위 유전자')
        for parent in echo.parents:
            print(parent.status, parent.similar)
 
        print('=======================\n\n')
        time.sleep(1)
cs


유전자의 총 갯수 유전자 길이등을 설정하는 인자를 넘길수 있게 수정을 하였다.

(디버깅 할때 편하게 하려고 sleep을 추가해 주었다)



프로그램이 끝이나면 모든 유전자는 사망을한다.

(테스트 진행중에는 평균적으로 10~20정도에 완료가 됬는데 6번만에 끝났네 ㅋㅋㅋㅋㅋ)

Gends 클래스에 



1
2
 def __del__(self):
        print(self.status, '사망')
cs


추가만 해주면 된다.


그냥 글 보고 그대로 짜긴 했는데

아직은 잘 모르겠다.

보니깐 교차방법 변이방법이 종류가 다양하던데 ㅋㅋㅋㅋㅋ 심심할때 짜긴 좋은거 같긴하다.




먼가 코드가 맘에 안들면 수정해서 알려주십쇼~~ ㅋㅋ


https://github.com/pjt3591oo/python-gene



Comments