โจ 3 - Selection ์ ํ
Selection is the choice of those individuals that will participate in creating offspring for the next population, that is, for the next generation.
์ ํ์ ๋ค์ ์ธ๋์ ๊ฐ์ฒด๊ตฐ์ ์์ฑํ๋ ๋ฐ ์ฐธ์ฌํ ๊ฐ์ฒด๋ค์ ์ ํํ๋ ๊ณผ์ , ์ฆ ๋ค์ ์ธ๋๋ฅผ ์ํ ๊ฐ์ฒด๋ค์ ๊ณ ๋ฅด๋ ๊ฒ์ ์๋ฏธํฉ๋๋ค.
Such a choice is made by the principle of natural selection, according to which the most adapted individuals have the highest chances of participating in the creation of new individuals.
์ด๋ฌํ ์ ํ์ ์์ฐ ์ ํ์ ์๋ฆฌ์ ๋ฐ๋ผ ์ด๋ฃจ์ด์ง๋ฉฐ, ์ด ์๋ฆฌ์ ๋ฐ๋ฅด๋ฉด ๊ฐ์ฅ ์ ์ ์ํ ๊ฐ์ฒด๋ค์ด ์๋ก์ด ๊ฐ์ฒด ์์ฑ์ ์ฐธ์ฌํ ๊ฐ๋ฅ์ฑ์ด ๊ฐ์ฅ ๋์ต๋๋ค.
As a result, an intermediate population (or parent pool) appears.
๊ทธ ๊ฒฐ๊ณผ๋ก ์ค๊ฐ ๊ฐ์ฒด๊ตฐ(๋๋ ๋ถ๋ชจ ํ)์ด ํ์ฑ๋ฉ๋๋ค.
An intermediate population is a set of individuals that have acquired the right to breed.
์ค๊ฐ ๊ฐ์ฒด๊ตฐ์ ๋ฒ์ํ ๊ถ๋ฆฌ๋ฅผ ํ๋ํ ๊ฐ์ฒด๋ค์ ์งํฉ์
๋๋ค.
Adapted individuals can be recorded there several times.
์ ์๋ ๊ฐ์ฒด๋ ์ด ์ค๊ฐ ๊ฐ์ฒด๊ตฐ์ ์ฌ๋ฌ ๋ฒ ํฌํจ๋ ์ ์์ต๋๋ค.
The abandoned individuals will most likely not get there at all.
์ ํ๋์ง ์์ ๊ฐ์ฒด๋ค์ ๋๋ถ๋ถ ์ด ์งํฉ์ ํฌํจ๋์ง ๋ชปํ ๊ฒ์
๋๋ค.
NOTE : It is important to understand that the same individual can be selected several times by the selection method, which means it can repeatedly participate in the process of creating new individuals.
์ฐธ๊ณ : ๋์ผํ ๊ฐ์ฒด๊ฐ ์ ํ ๋ฐฉ์์ ๋ฐ๋ผ ์ฌ๋ฌ ๋ฒ ์ ํ๋ ์ ์๋ค๋ ์ ์ ์ดํดํ๋ ๊ฒ์ด ์ค์ํ๋ฉฐ, ์ด๋ ๊ทธ ๊ฐ์ฒด๊ฐ ๋ฐ๋ณต์ ์ผ๋ก ์๋ก์ด ๊ฐ์ฒด ์์ฑ ๊ณผ์ ์ ์ฐธ์ฌํ ์ ์๋ค๋ ๊ฒ์ ์๋ฏธํฉ๋๋ค.
๐ก ์ฃผ์ ๋จ์ด
| ์์ด ๋จ์ด | ํ๊ธ ๋ป |
|---|---|
| participate | ์ฐธ์ฌํ๋ค |
| intermediate population | ์ค๊ฐ ๊ฐ์ฒด๊ตฐ |
| parent pool | ๋ถ๋ชจ ํ |
| right | ๊ถ๋ฆฌ |
| acquire | ํ๋ํ๋ค |
| breed | ๋ฒ์ํ๋ค |
| abandoned | ๋ฒ๋ ค์ง, ์ ํ๋์ง ์์ ๊ฐ์ฒด |
| repeatedly | ๋ฐ๋ณต์ ์ผ๋ก |
โจ 3 - Structure ๊ตฌ์กฐ
In this chapter, we will look at the following selection methods:
์ด๋ฒ ์ฅ์์๋ ๋ค์๊ณผ ๊ฐ์ ์ ํ ๋ฐฉ๋ฒ๋ค์ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
Tournament selection
ํ ๋๋จผํธ ์ ํ
Proportional selection
๋น๋ก ์ ํ
Stochastic universal sampling selection
ํ๋ฅ ์ ์ ์ญ ์ํ๋ง ์ ํ
Rank selection
์์ ๊ธฐ๋ฐ ์ ํ
Elite selection
์๋ฆฌํธ ์ ํ
โจ 3 - Objectives ํ์ต ๋ชฉํ
Introduce basic selection methods
๊ธฐ๋ณธ์ ์ธ ์ ํ ๋ฐฉ๋ฒ๋ค์ ์๊ฐํฉ๋๋ค.
Understand key features of each method
๊ฐ ๋ฐฉ๋ฒ์ ํต์ฌ ํน์ง์ ์ดํดํฉ๋๋ค.
Get practical examples
์ค์ฉ์ ์ธ ์์ ๋ค์ ์ดํด๋ด
๋๋ค.
โจ 3.1 Tournament selection ํ ๋๋จผํธ ์ ํ
Tournament selection is one of the simplest selection methods, and we will start with it.
ํ ๋๋จผํธ ์ ํ์ ๊ฐ์ฅ ๊ฐ๋จํ ์ ํ ๋ฐฉ์ ์ค ํ๋์ด๋ฉฐ, ์ด๋ฒ์๋ ์ด ๋ฐฉ๋ฒ๋ถํฐ ์์ํ๊ฒ ์ต๋๋ค.
In tournament selection, a subgroup is selected in a population, and then the best individual in this subgroup is selected.
ํ ๋๋จผํธ ์ ํ์์๋ ๊ฐ์ฒด๊ตฐ ๋ด์์ ํ๋์ ํ์ ์ง๋จ์ ์ ํํ ๋ค์, ๊ทธ ์ค ๊ฐ์ฅ ์ฐ์ํ ๊ฐ์ฒด๋ฅผ ์ ํํฉ๋๋ค.
Typically, the size of a subgroup is 2 or 3 individuals.
์ผ๋ฐ์ ์ผ๋ก ํ์ ์ง๋จ์ ํฌ๊ธฐ๋ 2๋ช
๋๋ 3๋ช
์
๋๋ค.
Tournament selection method can be illustrated by the following script
ํ ๋๋จผํธ ์ ํ ๋ฐฉ์์ ๋ค์๊ณผ ๊ฐ์ ์คํฌ๋ฆฝํธ๋ก ์ค๋ช
ํ ์ ์์ต๋๋ค.
Import part
import random
import pandas as pd
import matplotlib.pyplot as plt
from ch3.individual import Individual Tournament selection
POPULATION_SIZE = 10
TOURNAMENT_SIZE = 3
population = Individual.create_random_population(POPULATION_SIZE)
candidates = [random.choice(population) for _ in range(TOURNAMENT_SIZE)]
best = [max(candidates, key = lambda ind: ind.fitness)] Visualization
def plot_individuals(individual_set):
df = pd.DataFrame({
'name': [ind.name for ind in individual_set],
'fitness': [ind.fitness for ind in individual_set]
})
df.plot.bar(x = 'name', y = 'fitness', rot = 0)
plt.show()
plot_individuals(population)
plot_individuals(candidates)
plot_individuals(best) Letโs take a look at the following figure 3.1 for visualization of random population with fitness function:
๋ฌด์์ ๊ฐ์ฒด๊ตฐ๊ณผ ์ ํฉ๋ ํจ์๋ฅผ ์๊ฐํํ ๊ทธ๋ฆผ 3.1์ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
Say, we have the population as shown in the preceding figure,
์์ ์ ์๋ ๊ทธ๋ฆผ๊ณผ ๊ฐ์ ๊ฐ์ฒด๊ตฐ์ด ์๋ค๊ณ ๊ฐ์ ํด๋ด
์๋ค.
and we randomly choose three individuals from it โ A, I, D (refer to the following figure)
๊ทธ๋ฆฌ๊ณ ๊ทธ ๊ฐ์ฒด๊ตฐ์์ ๋ฌด์์๋ก A, I, D ์ธ ๊ฐ์ฒด๋ฅผ ์ ํํฉ๋๋ค (๋ค์ ๊ทธ๋ฆผ์ ์ฐธ์กฐํ์ธ์).
And as a result, the D individual is chosen.
๊ทธ ๊ฒฐ๊ณผ๋ก, D ๊ฐ์ฒด๊ฐ ์ ํ๋ฉ๋๋ค.
The tournament selection can be implemented the following way:
ํ ๋๋จผํธ ์ ํ์ ๋ค์๊ณผ ๊ฐ์ด ๊ตฌํํ ์ ์์ต๋๋ค:
import random
def selection_tournament(individuals, group_size=2):
selected = []
for _ in range(len(individuals)):
candidates = [random.choice(individuals) for _ in range(group_size)]
selected.append(max(candidates, key=lambda ind: ind.fitness))
return selectedNOTE: It is worth mentioning that if the group size is two, then the worst individual will never be selected; if the group size is three, then the two worst individuals will never be selected, and so on.
์ฐธ๊ณ : ๊ทธ๋ฃน ํฌ๊ธฐ๊ฐ 2๋ผ๋ฉด ๊ฐ์ฅ ๋์ ๊ฐ์ฒด๋ ์ ๋ ์ ํ๋์ง ์์ผ๋ฉฐ, ๊ทธ๋ฃน ํฌ๊ธฐ๊ฐ 3์ด๋ฉด ๊ฐ์ฅ ๋์ ๋ ๊ฐ์ฒด๋ ์ ๋ ์ ํ๋์ง ์์ต๋๋ค. ์ด์ ๊ฐ์ ๋ฐฉ์์ผ๋ก ์งํ๋ฉ๋๋ค.
Letโs see this method in action
์ด์ ์ด ๋ฐฉ๋ฒ์ ์ค์ ๋ก ์คํํด ๋ด
์๋ค.
import random
from ch3.selection_tournament import selection_tournament
from ch3.individual import Individual
POPULATION_SIZE = 5
random.seed(4)
population = Individual.create_random_population(POPULATION_SIZE)
selected = selection_tournament(population, group_size=3)
print(f"Population: {population}")
print(f"Selected: {selected}")Result
Population: [A: 3, B: 4, C: 1, D: 6, E: 7]
Selected: [B: 4, E: 7, B: 4, E: 7, B: 4]As expected, two worst individuals, A and C were not selected.
์์๋๋ก, ๊ฐ์ฅ ๋ฎ์ ์ ํฉ๋๋ฅผ ๊ฐ์ง A์ C๋ ์ ํ๋์ง ์์์ต๋๋ค.
But we have one more interesting result โ the individual D, which has the second fitness score, was also not selected.
ํ์ง๋ง ํฅ๋ฏธ๋ก์ด ์ ์, ๋ ๋ฒ์งธ๋ก ๋์ ์ ํฉ๋๋ฅผ ๊ฐ์ง D ๊ฐ์ฒด๋ ์ ํ๋์ง ์์๋ค๋ ๊ฒ์
๋๋ค.
You always have to keep in mind that the tournament selection is a random process, and there is no 100% guarantee that the best individual will be selected.
ํ ๋๋จผํธ ์ ํ์ ํญ์ ๋ฌด์์์ ์ธ ๊ณผ์ ์ด๋ผ๋ ์ ์ ๊ธฐ์ตํด์ผ ํ๋ฉฐ, ๊ฐ์ฅ ์ข์ ๊ฐ์ฒด๊ฐ ๋ฐ๋์ ์ ํ๋๋ค๋ ๋ณด์ฅ์ ์์ต๋๋ค.
๐ก ์ฃผ์ ๋จ์ด
| ์์ด ๋จ์ด | ํ๊ธ ๋ป |
|---|---|
| subgroup | ํ์ ์ง๋จ |
| typically | ์ผ๋ฐ์ ์ผ๋ก |
| implement | ๊ตฌํํ๋ค |
| script | ์คํฌ๋ฆฝํธ (์ฝ๋) |
| candidate | ํ๋ณด์, ํ๋ณด ๊ฐ์ฒด |
| guarantee | ๋ณด์ฅ |
โจ 3.2 Proportional selection ๋น๋ก ์ ํ
This method can be illustrated with a roulette wheel.
์ด ๋ฐฉ๋ฒ์ ๋ฃฐ๋ ํ ์ ํตํด ์ค๋ช
ํ ์ ์์ต๋๋ค.
Each individual is assigned a sector of the roulette wheel, the value of which is set proportional to the value of the fitness function of a given individual;
๊ฐ ๊ฐ์ฒด๋ ๋ฃฐ๋ ํ ์์ ํ๋์ ๊ตฌ์ญ์ ํ ๋น๋ฐ์ผ๋ฉฐ, ์ด ๊ตฌ์ญ์ ํฌ๊ธฐ๋ ํด๋น ๊ฐ์ฒด์ ์ ํฉ๋ ๊ฐ์ ๋น๋กํ์ฌ ๊ฒฐ์ ๋ฉ๋๋ค.
therefore, the greater the value of the fitness function, the larger the sector on the roulette wheel.
๋ฐ๋ผ์ ์ ํฉ๋ ๊ฐ์ด ํด์๋ก ๋ฃฐ๋ ์์ ์ฐจ์งํ๋ ๊ตฌ์ญ์ด ๋ ์ปค์ง๋๋ค.
From this, it follows that the larger the sector on the roulette wheel, the higher the chance that this particular individual will be chosen.
์ด๋ก ์ธํด ๊ตฌ์ญ์ด ํด์๋ก ํด๋น ๊ฐ์ฒด๊ฐ ์ ํ๋ ํ๋ฅ ์ด ๋์์ง๋๋ค.
Letโs examine the script showing the principle of this selection method
์ด ์ ํ ๋ฐฉ๋ฒ์ ์๋ฆฌ๋ฅผ ๋ณด์ฌ์ฃผ๋ ์คํฌ๋ฆฝํธ๋ฅผ ์ดํด๋ด
์๋ค.
Import part
import random
import pandas as pd
import matplotlib.pyplot as plt
from ch3.individual import IndividualProportional selection
random.seed(4)
POPULATION_SIZE = 5
unsorted_population = Individual.create_random_population(POPULATION_SIZE)
population = sorted(unsorted_population, key=lambda ind: ind.fitness, reverse=True)
fitness_sum = sum([ind.fitness for ind in population])
fitness_map = {}
for i in population:
i_prob = round(100 * i.fitness / fitness_sum)
i_label = f'{i.name} | fitness: {i.fitness}, prob: {i_prob}%'
fitness_map[i_label] = i.fitnessVisualization
index = ['Sectors']
df = pd.DataFrame(fitness_map, index=index)
df.plot.barh(stacked=True)
for _ in range(POPULATION_SIZE):
plt.axvline(x=random.random() * fitness_sum, linewidth=5, color='black')
plt.tick_params(axis='x', which='both', bottom=False, top=False, labelbottom=False)
plt.show()
Consider the preceding example, as shown in figure where individual B has a fitness score of 9.
์์ ๊ทธ๋ฆผ์์ B ๊ฐ์ฒด์ ์ ํฉ๋ ์ ์๊ฐ 9๋ผ๊ณ ๊ฐ์ ํด๋ด
์๋ค.
The total number of fitness scores is 17, the sector of individual B occupies 9/17 = 0.5294, that is, 53% of the entire roulette strip.
์ ์ฒด ์ ํฉ๋ ํฉ์ด 17์ผ ๋, B ๊ฐ์ฒด๋ ๋ฃฐ๋ ์คํธ๋ฆฝ์ 53%์ ํด๋นํ๋ 9/17 = 0.5294๋งํผ์ ๊ตฌ์ญ์ ์ฐจ์งํฉ๋๋ค.
The lengths of sectors for other individuals are calculated in the same way.
๋ค๋ฅธ ๊ฐ์ฒด๋ค์ ๊ตฌ์ญ ๊ธธ์ด๋ ๊ฐ์ ๋ฐฉ์์ผ๋ก ๊ณ์ฐ๋ฉ๋๋ค.
Black bars are the result of one roulette spin.
๊ฒ์ ๋ง๋๋ค์ ๋ฃฐ๋ ์ ํ ๋ฒ ๋๋ฆฐ ๊ฒฐ๊ณผ๋ฅผ ๋ํ๋
๋๋ค.
As a result, we have the following selection result: B, B, B, D, A
๊ทธ ๊ฒฐ๊ณผ๋ก ์ ํ๋ ๊ฐ์ฒด๋ค์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค: B, B, B, D, A
The proportional selection can be implemented in the following way:
๋น๋ก ์ ํ์ ๋ค์๊ณผ ๊ฐ์ด ๊ตฌํํ ์ ์์ต๋๋ค:
import random
def selection_proportional(individuals):
sorted_individuals = sorted(individuals, key=lambda ind: ind.fitness, reverse=True)
fitness_sum = sum([ind.fitness for ind in individuals])
selected = []
for _ in range(len(sorted_individuals)):
shave = random.random() * fitness_sum
roulette_sum = 0
for ind in sorted_individuals:
roulette_sum += ind.fitness
if roulette_sum > shave:
selected.append(ind)
break
return selectedLetโs see this selection method in action
์ด ์ ํ ๋ฐฉ๋ฒ์ ์ค์ ๋ก ์คํํด ๋ด
์๋ค.
import random
from ch3.selection_proportional import selection_proportional
from ch3.individual import Individual
POPULATION_SIZE = 5
random.seed(4)
population = Individual.create_random_population(POPULATION_SIZE)
selected = selection_proportional(population)
print(f"Population: {population}")
print(f"Selected: {selected}")Result
Population: [A: 3, B: 4, C: 1, D: 6, E: 7]
Selected: [E: 7, E: 7, D: 6, A: 3, B: 4]Proportional selection method has the possibility to select the worst individual, and also has the possibility to not select best individual.
๋น๋ก ์ ํ ๋ฐฉ์์ ์ฑ๋ฅ์ด ๊ฐ์ฅ ๋ฎ์ ๊ฐ์ฒด๊ฐ ์ ํ๋ ์ ์๊ณ , ๋ฐ๋๋ก ์ฑ๋ฅ์ด ๊ฐ์ฅ ์ข์ ๊ฐ์ฒด๊ฐ ์ ํ๋์ง ์์ ์๋ ์์ต๋๋ค.
๐ก ์ฃผ์ ๋จ์ด
| ์์ด ๋จ์ด | ํ๊ธ ๋ป |
|---|---|
| roulette wheel | ๋ฃฐ๋ ํ |
| sector | ๊ตฌ์ญ, ์์ญ |
| proportional | ๋น๋กํ๋ |
| assign | ํ ๋นํ๋ค |
| occupy | ์ฐจ์งํ๋ค |
โจ 3.3 Stochastic universal sampling selection ํ๋ฅ ์ ๋ณดํธ ์ํ๋ง
Stochastic universal sampling selection method is an alternative method of proportional selection.
ํ๋ฅ ์ ๋ณดํธ ์ํ๋ง(Stochastic Universal Sampling, SUS)์ ๋น๋ก ์ ํ ๋ฐฉ์์ ๋์์
๋๋ค.
In this method, the entire roulette wheel is divided into N cutoffs with equal spacing.
์ด ๋ฐฉ์์์๋ ์ ์ฒด ๋ฃฐ๋ ํ ์ด ๋์ผํ ๊ฐ๊ฒฉ์ ๊ฐ๋ N๊ฐ์ ๊ตฌ๊ฐ์ผ๋ก ๋๋ฉ๋๋ค.
This method smooths out the elements of randomness which proportional selection has,
์ด ๋ฐฉ๋ฒ์ ๋น๋ก ์ ํ์ด ๊ฐ์ง๋ ๋ฌด์์์ฑ์ ์ํ์์ผ์ฃผ๋ฉฐ,
and ensures that the individuals are selected according to the following principle โ many good individuals, some average individuals, and a few bad individuals.
์ข์ ๊ฐ์ฒด๋ ๋ง์ด, ํ๊ท ๊ฐ์ฒด๋ ์ ๋นํ, ๋์ ๊ฐ์ฒด๋ ์กฐ๊ธ๋ง ์ ํ๋๋๋ก ๋ณด์ฅํฉ๋๋ค.
It can be demonstrated as follows:
์ด ๋ฐฉ์์ ๋ค์๊ณผ ๊ฐ์ด ๊ตฌํํ ์ ์์ต๋๋ค:
Import part
import random
import pandas as pd
import matplotlib.pyplot as plt
from ch3.individual import IndividualSelection
POPULATION_SIZE = 5
random.seed(9)
unsorted_population = Individual.create_random_population(POPULATION_SIZE)
population = sorted(unsorted_population, key=lambda ind: ind.fitness, reverse=True)
fitness_sum = sum([ind.fitness for ind in population])
fitness_map = {}
for i in population:
i_prob = round(100 * i.fitness / fitness_sum)
i_label = f'{i.name} | fitness: {i.fitness}, prob: {i_prob}%'
fitness_map[i_label] = i.fitnessVisualization
index = ['Sectors']
df = pd.DataFrame(fitness_map, index=index)
df.plot.barh(stacked=True)
distance = fitness_sum / POPULATION_SIZE
shift = random.random() * distance
for i in range(POPULATION_SIZE):
plt.axvline(x=shift + distance * i, linewidth=5, color='black')
plt.tick_params(axis='x', which='both', bottom=False, top=False, labelbottom=False)
plt.show()Letโs take a look at the following figure 3.4 for the visualization of Stochastic universal sampling selection:
ํ๋ฅ ์ ๋ณดํธ ์ํ๋ง ์ ํ ๋ฐฉ์์ ์๊ฐ์ ์ผ๋ก ์ดํดํ๊ธฐ ์ํด ๊ทธ๋ฆผ 3.4๋ฅผ ์ดํด๋ด
์๋ค.
The stochastic universal sampling selection can be implemented in the following way:
ํ๋ฅ ์ ๋ณดํธ ์ํ๋ง ์ ํ ๋ฐฉ์์ ๋ค์๊ณผ ๊ฐ์ด ๊ตฌํํ ์ ์์ต๋๋ค:
import random
def selection_stochastic_universal_sampling(individuals):
sorted_individuals = sorted(individuals, key=lambda ind: ind.fitness, reverse=True)
fitness_sum = sum([ind.fitness for ind in individuals])
distance = fitness_sum / len(individuals)
shift = random.uniform(0, distance)
borders = [shift + i * distance for i in range(len(individuals))]
selected = []
for border in borders:
i = 0
roulette_sum = sorted_individuals[i].fitness
while roulette_sum < border:
i += 1
roulette_sum += sorted_individuals[i].fitness
selected.append(sorted_individuals[i])
return selectedLetโs see the stochastic universal sampling selection method in action
์ด์ ํ๋ฅ ์ ๋ณดํธ ์ํ๋ง ์ ํ ๋ฐฉ์์ ์ค์ ๋ก ์คํํด ๋ด
์๋ค.
import random
from ch3.selection_stochastic_universal_sampling import selection_stochastic_universal_sampling
from ch3.individual import Individual
POPULATION_SIZE = 5
random.seed(1)
population = Individual.create_random_population(POPULATION_SIZE)
selected = selection_stochastic_universal_sampling(population)
print(f"Population: {population}")
print(f"Selected: {selected}")Result
Population: [A: 2, B: 9, C: 1, D: 4, E: 1]
Selected: [B: 9, B: 9, B: 9, D: 4, C: 1]NOTE: As with the proportional selection method, the stochastic universal sampling selection has the possibility to select the worst individual, and also has the possibility to not select the best individual.
์ฐธ๊ณ : ๋น๋ก ์ ํ ๋ฐฉ์๊ณผ ๋ง์ฐฌ๊ฐ์ง๋ก, ํ๋ฅ ์ ๋ณดํธ ์ํ๋ง๋ ์ต์
์ ๊ฐ์ฒด๊ฐ ์ ํ๋ ์ ์์ผ๋ฉฐ, ์ต์์ ๊ฐ์ฒด๊ฐ ์ ํ๋์ง ์์ ์๋ ์์ต๋๋ค.
Even if it seems contradictory, this approach shows very good results for a particular class of problems.
๋ชจ์์ ์ผ๋ก ๋ณด์ผ ์ ์์ง๋ง, ์ด ๋ฐฉ์์ ํน์ ์ ํ์ ๋ฌธ์ ๋ค์์ ๋งค์ฐ ์ข์ ์ฑ๋ฅ์ ๋ณด์
๋๋ค.
๐ก ์ฃผ์ ๋จ์ด
| ์์ด ๋จ์ด | ํ๊ธ ๋ป |
|---|---|
| stochastic | ํ๋ฅ ์ ์ธ |
| universal | ๋ณดํธ์ ์ธ |
| sampling | ์ํ๋ง, ํ๋ณธ ์ถ์ถ |
| alternative | ๋์ |
| cutoff | ๊ฒฝ๊ณ์ , ์๋ผ์ง๋ ์ง์ |
| smooth out | ์ํํ๋ค, ๋ถ๋๋ฝ๊ฒ ํ๋ค |
| randomness | ๋ฌด์์์ฑ |
| ensure | ๋ณด์ฅํ๋ค |
| sector | ๊ตฌ์ญ, ์์ญ |
| border | ๊ฒฝ๊ณ ์์น |
| contradictory | ๋ชจ์์ ์ธ |
โจ 3.4 Rank selection ์์ ์ ํ
Rank selection has the same principle as proportional selection, but individuals of the population are ranked according to the values of their fitness function.
์์ ์ ํ(Rank Selection)์ ๋น๋ก ์ ํ๊ณผ ๊ฐ์ ์๋ฆฌ๋ฅผ ๋ฐ๋ฅด์ง๋ง, ๊ฐ์ฒด๋ค์ ์ ํฉ๋ ๊ฐ์ ๋ฐ๋ผ ์์๋ก ์ ๋ ฌํ๋ค๋ ์ ์์ ์ฐจ์ด๊ฐ ์์ต๋๋ค.
This can be thought of as a sorted list of individuals, ordered from the fittest to the least fit, in which each individual is assigned a number that determines its place in the list, called rank.
์ด ๋ฐฉ์์ ๊ฐ์ฒด๋ค์ ๊ฐ์ฅ ์ ํฉํ ์์๋ถํฐ ๋ ์ ํฉํ ์์๋๋ก ์ ๋ ฌํ ๋ฆฌ์คํธ๋ก ์๊ฐํ ์ ์์ผ๋ฉฐ, ๊ฐ ๊ฐ์ฒด๋ ํด๋น ์์๋ฅผ ๋ํ๋ด๋ โ์์(rank)โ๋ฅผ ๋ถ์ฌ๋ฐ์ต๋๋ค.
Rank selection smoothens out the large difference between individuals with high fitness values and individuals with low fitness values.
์์ ์ ํ์ ๋์ ์ ํฉ๋์ ๋ฎ์ ์ ํฉ๋ ์ฌ์ด์ ํฐ ์ฐจ์ด๋ฅผ ์ํํด์ฃผ๋ ํจ๊ณผ๊ฐ ์์ต๋๋ค.
Letโs compare proportion selection with rank selection
๋น๋ก ์ ํ๊ณผ ์์ ์ ํ์ ๋น๊ตํด ๋ด
์๋ค.
Import part
import random
import pandas as pd
import matplotlib.pyplot as plt
from ch3.individual import IndividualRank selection
POPULATION_SIZE = 5
random.seed(2)
unsorted_population = Individual.create_random_population(POPULATION_SIZE)
population = sorted(unsorted_population, key=lambda ind: ind.fitness, reverse=True)
fitness_sum = sum([ind.fitness for ind in population])
fitness_map = {}
for i in population:
i_prob = round(100 * i.fitness / fitness_sum)
i_label = f'{i.name} | fitness: {i.fitness}, prob: {i_prob}%'
fitness_map[i_label] = i.fitness
proportional_df = pd.DataFrame(fitness_map, index=['Sectors'])
proportional_df.plot.barh(stacked=True)
plt.tick_params(axis='x', which='both', bottom=False, top=False, labelbottom=False)
plt.title('Fitness Proportional Sectors')
plt.show()Rank-based probabilities and visualization
rank_step = 1 / POPULATION_SIZE
rank_sum = sum([1 - rank_step * i for i in range(len(population))])
rank_map = {}
for i in range(len(population)):
i_rank = i + 1
i_rank_proportion = 1 - i * rank_step
i_prob = round(100 * i_rank_proportion / rank_sum)
i_label = f'{population[i].name} | rank: {i_rank}, prob: {i_prob}%'
rank_map[i_label] = i_rank_proportion
rank_df = pd.DataFrame(rank_map, index=['Sectors'])
rank_df.plot.barh(stacked=True)
plt.tick_params(axis='x', which='both', bottom=False, top=False, labelbottom=False)
plt.title('Rank Proportional Sectors')
plt.show()We already saw that proportional selection uses the roulette sectors, as shown in the following figure.
์ฐ๋ฆฌ๋ ์ด๋ฏธ ๋น๋ก ์ ํ์ด ๋ฃฐ๋ ๊ตฌ์ญ์ ์ฌ์ฉํ๋ ๋ฐฉ์์ ์์ ๊ทธ๋ฆผ์์ ์ดํด๋ณธ ๋ฐ ์์ต๋๋ค.
But for the same population, rank selection will use the following roulette (as shown in the following figure): ํ์ง๋ง ๋์ผํ ๊ฐ์ฒด๊ตฐ์ ๋ํด์, ์์ ์ ํ์ ๋ค์ ๊ทธ๋ฆผ๊ณผ ๊ฐ์ ๋ฃฐ๋ ์ ์ฌ์ฉํฉ๋๋ค.
We see that the best individual in rank selection has a lower chance of being selected than it has in the proportional selection,
์์ ์ ํ์์๋ ๊ฐ์ฅ ์ฐ์ํ ๊ฐ์ฒด๊ฐ ๋น๋ก ์ ํ๋ณด๋ค ์ ํ๋ ํ๋ฅ ์ด ๋ ๋ฎ์ต๋๋ค.
and on the contrary, the worst individual, which had no chance of being selected in proportional selection has some positive probability of being selected.
๋ฐ๋๋ก, ๋น๋ก ์ ํ์์๋ ์ ํ๋ ๊ฐ๋ฅ์ฑ์ด ์์๋ ์ต์
์ ๊ฐ์ฒด๋ ์์ ์ ํ์์๋ ์ผ์ ํ๋ฅ ๋ก ์ ํ๋ ์ ์์ต๋๋ค.
How is rank selection calculated?
์์ ์ ํ ํ๋ฅ ์ ์ด๋ป๊ฒ ๊ณ์ฐ๋ ๊น์?
rank_shift := 1 / population_size = 1 / 5 = 0.2
rank_weight_sum := (population_size + 1) / 2 = 3
Nth_individual_weight := (1 โ (rank - 1) ร rank_shift) / rank_weight_sum ร 100%For D we have (1 โ (0 ร 0.2)) / 3 ร 100% = 33%
D์ ๊ฒฝ์ฐ: (1 โ (0 ร 0.2)) / 3 ร 100% = 33%
For E we have (1 โ (1 ร 0.2)) / 3 ร 100% = 27%
E์ ๊ฒฝ์ฐ: (1 โ (1 ร 0.2)) / 3 ร 100% = 27%
For B we have (1 โ (2 ร 0.2)) / 3 ร 100% = 20%
B์ ๊ฒฝ์ฐ: (1 โ (2 ร 0.2)) / 3 ร 100% = 20%
Rank selection implementation
import random
def selection_rank(individuals):
sorted_individuals = sorted(individuals, key=lambda ind: ind.fitness, reverse=True)
rank_distance = 1 / len(individuals)
ranks = [(1 - i * rank_distance) for i in range(len(individuals))]
ranks_sum = sum(ranks)
selected = []
for _ in range(len(sorted_individuals)):
shave = random.random() * ranks_sum
rank_sum = 0
for i in range(len(sorted_individuals)):
rank_sum += ranks[i]
if rank_sum > shave:
selected.append(sorted_individuals[i])
break
return selectedLetโs examine how rank selection works
์์ ์ ํ์ด ์ด๋ป๊ฒ ์๋ํ๋์ง ์ดํด๋ด
์๋ค.
import random
from ch3.selection_rank import selection_rank
from ch3.individual import Individual
POPULATION_SIZE = 5
random.seed(18)
population = Individual.create_random_population(POPULATION_SIZE)
selected = selection_rank(population)
print(f'Population: {population}')
print(f'Selected: {selected}')Result
Population: [A: 2, B: 1, C: 10, D: 7, E: 5]
Selected: [C: 10, B: 1, E: 5, C: 10, C: 10]๐ก ์ฃผ์ ๋จ์ด
| ์์ด ๋จ์ด | ํ๊ธ ๋ป |
|---|---|
| smoothen (smooth out) | ์ํํ๋ค, ๋ถ๋๋ฝ๊ฒ ๋ง๋ค๋ค |
| comparison | ๋น๊ต |
| weight | ๊ฐ์ค์น |
| probability formula | ํ๋ฅ ๊ณต์ |
| positive probability | 0๋ณด๋ค ํฐ ํ๋ฅ |
โจ 3.5 Elite selection ์๋ฆฌํธ ์ ํ
As we have already seen, none of the selection methods that we have considered โ tournament, proportional, stochastic universal sampling, and rank selection โ guarantee the selection of the best individual.
์ง๊ธ๊น์ง ์ดํด๋ณธ ํ ๋๋จผํธ, ๋น๋ก, ํ๋ฅ ์ ๋ณดํธ ์ํ๋ง, ์์ ์ ํ ๋ฐฉ์ ์ค ์ด๋ ๊ฒ๋ ์ต์์ ๊ฐ์ฒด๊ฐ ๋ฐ๋์ ์ ํ๋๋ค๋ ๋ณด์ฅ์ ํด์ฃผ์ง ์์ต๋๋ค.
The genes of the best individual can be very valuable for the next generations, so there is an approach that protects the best individuals.
๊ฐ์ฅ ์ฐ์ํ ๊ฐ์ฒด์ ์ ์ ์๋ ๋ค์ ์ธ๋์ ๋งค์ฐ ์ ์ฉํ ์ ์์ผ๋ฏ๋ก, ์ด๋ค์ ๋ณดํธํ๋ ์ ๊ทผ ๋ฐฉ์์ด ์กด์ฌํฉ๋๋ค.
This method is called elite selection.
์ด ๋ฐฉ๋ฒ์ ์๋ฆฌํธ ์ ํ(Elite Selection) ์ด๋ผ๊ณ ํฉ๋๋ค.
Elite selection can be based on another method, such as rank selection, but the main change in this method is the guaranteed inclusion of the best individuals in the selected population.
์๋ฆฌํธ ์ ํ์ ์์ ์ ํ ๊ฐ์ ๊ธฐ์กด ์ ํ ๋ฐฉ์ ์์ ๊ธฐ๋ฐํ ์ ์์ง๋ง, ํต์ฌ์ ์ธ ์ฐจ์ด๋ ๊ฐ์ฅ ์ฐ์ํ ๊ฐ์ฒด๋ค์ ๋ฐ๋์ ๋ค์ ์ธ๋์ ํฌํจ์ํจ๋ค๋ ์ ์
๋๋ค.
Elite selection implementation
import random
def selection_rank_with_elite(individuals, elite_size=0):
sorted_individuals = sorted(individuals, key=lambda ind: ind.fitness, reverse=True)
rank_distance = 1 / len(individuals)
ranks = [(1 - i * rank_distance) for i in range(len(individuals))]
ranks_sum = sum(ranks)
selected = sorted_individuals[0:elite_size]
for i in range(len(sorted_individuals) - elite_size):
shave = random.random() * ranks_sum
rank_sum = 0
for i in range(len(sorted_individuals)):
rank_sum += ranks[i]
if rank_sum > shave:
selected.append(sorted_individuals[i])
break
return selectedLetโs see this method in action
์ด์ ์ด ๋ฐฉ๋ฒ์ ์ค์ ๋ก ์คํํด ๋ด
์๋ค.
import random
from ch3.selection_rank_with_elite import selection_rank_with_elite
from ch3.individual import Individual
POPULATION_SIZE = 5
random.seed(3)
population = Individual.create_random_population(POPULATION_SIZE)
selected = selection_rank_with_elite(population, elite_size=2)
print(f"Population: {population}")
print(f"Selected: {selected}")Result
Population: [A: 3, B: 9, C: 8, D: 2, E: 5]
Selected: [B: 9, C: 8, A: 3, C: 8, C: 8]As we see B and C are the two best individuals in population, they form the elite and are being selected by default.
์ ๊ฒฐ๊ณผ์์ ๋ณผ ์ ์๋ฏ์ด, B์ C๋ ๊ฐ์ฒด๊ตฐ์์ ๊ฐ์ฅ ์ฐ์ํ ๋ ๊ฐ์ฒด์ด๋ฉฐ, ์๋ฆฌํธ๋ก ๊ฐ์ฃผ๋์ด ๊ธฐ๋ณธ์ ์ผ๋ก ์ ํ๋ฉ๋๋ค.
NOTE: Elite selection is a handy method of selection in conditions where an individualโs fitness may degenerate as a result of crossover or mutation.
์ฐธ๊ณ : ์๋ฆฌํธ ์ ํ์ ๊ต์ฐจ๋ ๋์ฐ๋ณ์ด๋ก ์ธํด ๊ฐ์ฒด์ ์ ํฉ๋๊ฐ ๋จ์ด์ง ์ ์๋ ์ํฉ์์ ์ ์ฉํ ์ ํ ๋ฐฉ์์
๋๋ค.
We need to protect the best individuals, and try to spread their genes among the population.
์ฐ๋ฆฌ๋ ์ต์์ ๊ฐ์ฒด๋ฅผ ๋ณดํธํ๊ณ , ๊ทธ๋ค์ ์ ์ ์๋ฅผ ๊ฐ์ฒด๊ตฐ์ ๋๋ฆฌ ํผ๋จ๋ ค์ผ ํฉ๋๋ค.
๐ก ์ฃผ์ ๋จ์ด
| ์์ด ๋จ์ด | ํ๊ธ ๋ป |
|---|---|
| guarantee | ๋ณด์ฅํ๋ค |
| inclusion | ํฌํจ |
| protect | ๋ณดํธํ๋ค |
| valuable | ๊ฐ์น ์๋ |
| by default | ๊ธฐ๋ณธ์ ์ผ๋ก, ์๋์ผ๋ก |
| degenerate | ํดํํ๋ค, ์ฝํ๋๋ค |
| handy | ์ ์ฉํ |
โจ 3 - Conclusion ๊ฒฐ๋ก
Selection is a very important part of the evolution process; every individual aims to generate an offspring.
์ ํ์ ์งํ ๊ณผ์ ์์ ๋งค์ฐ ์ค์ํ ๋ถ๋ถ์ด๋ฉฐ, ๋ชจ๋ ๊ฐ์ฒด๋ ์์์ ๋จ๊ธฐ๋ ๊ฒ์ ๋ชฉํ๋ก ํฉ๋๋ค.
The selection process is random by nature.
์ ํ ๊ณผ์ ์ ๋ณธ์ง์ ์ผ๋ก ๋ฌด์์์ ์
๋๋ค.
We have studied several selection methods, each of which has its pros and cons.
์ฐ๋ฆฌ๋ ์ฌ๋ฌ ๊ฐ์ง ์ ํ ๋ฐฉ๋ฒ๋ค์ ์ดํด๋ณด์๊ณ , ๊ฐ๊ฐ์ ๋ฐฉ์์ ์ฅ๋จ์ ์ ๊ฐ์ง๊ณ ์์ต๋๋ค.
You can use one of these methods or any modification.
์ด ์ค ํ๋์ ๋ฐฉ๋ฒ์ ์ฌ์ฉํ ์๋ ์๊ณ , ์์ ๋ ๋ฐฉ์๋ ์ฌ์ฉํ ์ ์์ต๋๋ค.
In the next chapter, we will study the next part of evolution called crossover.
๋ค์ ์ฅ์์๋ ์งํ์ ๋ค์ ๋จ๊ณ์ธ ๊ต์ฐจ(crossover)์ ๋ํด ๋ฐฐ์๋ณด๊ฒ ์ต๋๋ค.
โจ 3 - Points to remember: ๊ธฐ์ตํ ์
Each selection method has the following principle โ adapted individuals have a higher possibility to be selected than the abandoned ones.
๊ฐ ์ ํ ๋ฐฉ์์ ๋ค์ ์์น์ ๋ฐ๋ฆ
๋๋ค โ ๋ ์ ์๋ ๊ฐ์ฒด๊ฐ ๊ทธ๋ ์ง ๋ชปํ ๊ฐ์ฒด๋ณด๋ค ์ ํ๋ ๊ฐ๋ฅ์ฑ์ด ๋ ๋์ต๋๋ค.
Even abandoned individuals can have something valuable in their genes, so we have to leave a positive probability for them to be selected.
ํ์ง๋ง ๋ ์ ํฉํ ๊ฐ์ฒด๋ค๋ ์ ์ ์ ์ผ๋ก ๊ฐ์น ์๋ ์ ๋ณด๋ฅผ ๊ฐ์ง ์ ์๊ธฐ ๋๋ฌธ์, ๊ทธ๋ค์ด ์ ํ๋ ์ ์๋ ์ผ์ ํ ํ๋ฅ ์ ๋ฐ๋์ ๋จ๊ฒจ๋์ด์ผ ํฉ๋๋ค.
โจ 3 - Multiple choice questions ๊ฐ๊ด์ ๋ฌธ์
1. Which selection method guarantees that the best individual will be selected?
์ด๋ค ์ ํ ๋ฐฉ์์ด ์ต์์ ๊ฐ์ฒด๊ฐ ์ ํ๋ ๊ฒ์ ๋ณด์ฅํ๋์?
- Rank selection
์์ ์ ํ - Elite selection โ
์๋ฆฌํธ ์ ํ โ - Tournament selection
ํ ๋๋จผํธ ์ ํ - Proportional selection
๋น๋ก ์ ํ
2. Which selection method guarantees that the worst individual will not be selected?
์ด๋ค ์ ํ ๋ฐฉ์์ด ์ต์
์ ๊ฐ์ฒด๊ฐ ์ ํ๋์ง ์์ ๊ฒ์ ๋ณด์ฅํ๋์?
- Rank selection
์์ ์ ํ - Elite selection
์๋ฆฌํธ ์ ํ - Tournament selection โ
ํ ๋๋จผํธ ์ ํ โ - Proportional selection
๋น๋ก ์ ํ
3. Say we have the following population: A: 3, B: 9, C: 8, D: 2, E: 5.
๋ค์๊ณผ ๊ฐ์ ๊ฐ์ฒด๊ตฐ์ด ์๋ค๊ณ ๊ฐ์ ํฉ์๋ค: A: 3, B: 9, C: 8, D: 2, E: 5
And we have selected population: B: 9, C: 8, A: 3, C: 8, C: 8.
์ ํ๋ ๊ฐ์ฒด๊ตฐ์ด ๋ค์๊ณผ ๊ฐ๋ค๋ฉด: B: 9, C: 8, A: 3, C: 8, C: 8
What selection method have we used?
์ด๋ค ์ ํ ๋ฐฉ์์ด ์ฌ์ฉ๋์์๊น์?
-
Elite selection
์๋ฆฌํธ ์ ํ -
Proportional selection
๋น๋ก ์ ํ -
Itโs impossible to answer this question, it can be any of selection methods โ
์ด ์ง๋ฌธ์๋ ๋ตํ ์ ์์ต๋๋ค. ์ด๋ค ๋ฐฉ์์ด๋ ๊ฐ๋ฅ์ฑ์ด ์์ต๋๋ค. โ -
์ต์์ ๊ฐ์ฒด B์ C๊ฐ ํญ์ ํฌํจ๋์ด ์๋ ๊ฒ์ผ๋ก ๋ณด์ ์๋ฆฌํธ ์ ํ์ผ ๊ฐ๋ฅ์ฑ์ด ๊ฐ์ฅ ํผ