[1,1,1,1,...]
と全ての遺伝子が1になる染色体が答え。import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
import sys
from IPython.display import clear_output
def create_choromosome(GENES_LENGTH):
"""
染色体クラス。0か1の情報遺伝子をGENES_LENGTH分持つ。
input:
GENES_LENGTH(int): 1染色体に入る遺伝子の数
output:
choromosome(np.array): 染色体
note:
今回の遺伝子情報は0と1だけなので遺伝子を計算する関数は省く。
"""
return np.random.randint(0, 2, GENES_LENGTH)
def create_individual(GENES_LENGTH):
"""
個体を作成する関数。今回の個体は染色体がひとつなので、染色体=個体になっている
"""
choromosome = create_choromosome(GENES_LENGTH)
return choromosome
def create_generation(POPURATIONS_NUMBER, GENES_LENGTH):
"""
世代を作る関数。
input:
POPURATIONS_NUMBER: 1世代の個体数
GENES_LENGTH(int): 遺伝子の長さ(n)
output:
generation(list): 個体クラスのリスト
"""
generation = []
for i in range(POPURATIONS_NUMBER):
individual = create_individual(GENES_LENGTH)
generation.append(individual)
return generation
def calc_fitness(choromosome):
""" 適応度を計算する。"""
fitness = choromosome.sum() / len(choromosome)
return fitness
def select_roulette(generation):
'''
ルーレット方式の親選択
input:
generation(list)
output:
parents(np.array)
'''
weights = [calc_fitness(individual) for individual in generation]
norm_weights = [fitness / sum(weights) for fitness in weights]
idxs = [i for i in range(len(generation))]
idx = np.random.choice(idxs, p=norm_weights)
parent = generation[idx]
return parent
def select_tournament(generation, TOURNAMENT_SIZE):
'''
トーナメント方式の親選択
input:
generation(list)
TOURNAMENT_SIZE(int): ランダムに抽選される人数。
size(int): outputする親の数。デフォルトでは2人
output:
oarrents([np.array,...])
'''
idxs = [i for i in range(len(generation))]
random_idxs = np.random.choice(idxs, TOURNAMENT_SIZE, replace=False)
random_parents = [generation[idx] for idx in random_idxs]
parrent = max(random_parents, key=calc_fitness)
return parrent
二点交叉にはヒッチハイキングという欠点があり、遺伝子の数が増えるほど最適解が得られる確率が低くなる。
遺伝子の数に左右されることなく最適解が求められる
def crossover_two_point(mother,father):
'''
二点交叉をして子孫を返す。
入力:
混ぜ合わせたい個体のペア
出力:
交叉後の個体のペア
'''
size = len(mother)
point_befor = np.random.randint(0, size)
point_after = np.random.randint(0, size - 1)
if point_after >= point_befor:
point_after += 1
else:
point_befor, point_after = point_after, point_befor
choromosome = father
choromosome[point_befor:point_after] = mother[point_befor:point_after]
child = choromosome
return child
def crossover_uniform(mother,father):
'''
一様交叉をして子孫を返す。
入力:
混ぜ合わせたい個体のペア
出力:
交叉後の個体のペア
'''
choromosome = []
for i in range(len(mother)):
if np.random.random() < 0.5:
choromosome.append(father[i])
else:
choromosome.append(mother[i])
child = np.array(choromosome)
return child
変異確率について
種類
def mutation(child,MUTATION_PLOB):
if np.random.rand() < MUTATION_PLOB*0.01:
i = np.random.randint(0, len(child)-1)
child[i] = int(not child[i])
else:
return child
return child
# param
POPURATIONS_NUMBER = 100 #@param {type:"number"}
GENES_LENGTH = 100 #@param {type:"number"}
GENERATION_COUNT = 20 #@param {type:"number"}
TOURNAMENT_SIZE = 3 #@param {type:"number"}
MUTATION_PLOB = 1 #@param {type:"number"}
# 祖先となる世代を作成
generation = create_generation(POPURATIONS_NUMBER, GENES_LENGTH)
plot_max = []
plot_min = []
# ここから進化開始
for generation_number in range(GENERATION_COUNT):
next_generation = []
for i in range(len(generation)):
# mother = select_roulette(generation)
# father = select_roulette(generation)
mother = select_tournament(generation, TOURNAMENT_SIZE)
father = select_tournament(generation, TOURNAMENT_SIZE)
# child = crossover_two_point(mother,father)
child = crossover_uniform(mother,father)
child = mutation(child,MUTATION_PLOB)
next_generation.append(child)
fitness = [calc_fitness(choromosome) for choromosome in generation]
clear_output(wait=True)
print("第",generation_number+1,"/",GENERATION_COUNT,"世代")
print("適応度 : 最大",max(fitness),", 最小",min(fitness))
plot_max.append(max(fitness))
plot_min.append(min(fitness))
generation = next_generation
plt.plot(plot_max)
plt.plot(plot_min)
plt.show()