best for now RMSE: 30.937
This commit is contained in:
@@ -37,3 +37,62 @@ def grow_mutation(chromosome: Chromosome, max_depth: int) -> Chromosome:
|
||||
chromosome.root = subtree
|
||||
|
||||
return chromosome
|
||||
|
||||
|
||||
def node_replacement_mutation(chromosome: Chromosome) -> Chromosome:
|
||||
"""Мутация замены операции (Node Replacement Mutation).
|
||||
|
||||
Выбирает случайный узел с операцией (arity > 0) и заменяет его
|
||||
на случайную другую операцию той же арности, сохраняя поддеревья.
|
||||
|
||||
Если подходящей альтернативы нет — возвращает копию без изменений.
|
||||
"""
|
||||
chromosome = chromosome.copy()
|
||||
|
||||
operation_nodes = [n for n in chromosome.root.list_nodes() if n.value.arity > 0]
|
||||
if not operation_nodes:
|
||||
return chromosome
|
||||
|
||||
target_node = random.choice(operation_nodes)
|
||||
current_arity = target_node.value.arity
|
||||
|
||||
same_arity_ops = [
|
||||
op
|
||||
for op in chromosome.operations
|
||||
if op.arity == current_arity and op != target_node.value
|
||||
]
|
||||
if not same_arity_ops:
|
||||
return chromosome
|
||||
|
||||
new_operation = random.choice(same_arity_ops)
|
||||
|
||||
target_node.value = new_operation
|
||||
|
||||
return chromosome
|
||||
|
||||
|
||||
def hoist_mutation(chromosome: Chromosome) -> Chromosome:
|
||||
"""Hoist-мутация (анти-bloat).
|
||||
|
||||
Выбирает случайное поддерево, затем внутри него — случайное поддерево меньшей глубины,
|
||||
и заменяет исходное поддерево на это внутреннее.
|
||||
|
||||
В результате дерево становится короче, сохраняя часть структуры.
|
||||
"""
|
||||
chromosome = chromosome.copy()
|
||||
|
||||
operation_nodes = [n for n in chromosome.root.list_nodes() if n.value.arity > 0]
|
||||
if not operation_nodes:
|
||||
return chromosome
|
||||
|
||||
outer_subtree = random.choice(operation_nodes)
|
||||
outer_nodes = outer_subtree.list_nodes()[1:] # исключаем корень
|
||||
|
||||
inner_subtree = random.choice(outer_nodes).copy_subtree()
|
||||
|
||||
if outer_subtree.parent:
|
||||
outer_subtree.parent.replace_child(outer_subtree, inner_subtree)
|
||||
else:
|
||||
chromosome.root = inner_subtree
|
||||
|
||||
return chromosome
|
||||
|
||||
@@ -36,6 +36,7 @@ class Node:
|
||||
return node
|
||||
|
||||
def list_nodes(self) -> list[Node]:
|
||||
"""Список всех узлов поддерева, начиная с текущего (aka depth-first-search)."""
|
||||
nodes: list[Node] = [self]
|
||||
for child in self.children:
|
||||
nodes.extend(child.list_nodes())
|
||||
|
||||
@@ -26,3 +26,63 @@ def roulette_selection(population: Population, fitnesses: Fitnesses) -> Populati
|
||||
selected.append(population[idx])
|
||||
|
||||
return selected
|
||||
|
||||
|
||||
def tournament_selection(
|
||||
population: Population,
|
||||
fitnesses: Fitnesses,
|
||||
k: int = 3,
|
||||
) -> Population:
|
||||
"""Турнирная селекция.
|
||||
|
||||
В каждом турнире случайно выбирается k особей, и побеждает та,
|
||||
у которой лучшее (наибольшее) значение фитнеса. Для минимизации
|
||||
значения фитнеса нужно предварительно инвертировать.
|
||||
|
||||
Args:
|
||||
population: список особей (Population)
|
||||
fitnesses: список или массив фитнесов (Fitnesses)
|
||||
k: размер турнира
|
||||
|
||||
Returns:
|
||||
Новая популяция того же размера
|
||||
"""
|
||||
size = len(population)
|
||||
selected = []
|
||||
for _ in range(size):
|
||||
idxs = np.random.choice(size, size=k, replace=False)
|
||||
|
||||
fits = fitnesses[idxs]
|
||||
|
||||
winner_idx = idxs[np.argmax(fits)]
|
||||
selected.append(population[winner_idx])
|
||||
return selected
|
||||
|
||||
|
||||
def stochastic_tournament_selection(
|
||||
population: Population,
|
||||
fitnesses: Fitnesses,
|
||||
k: int = 3,
|
||||
p_best: float = 0.75,
|
||||
) -> Population:
|
||||
"""Стохастическая турнирная селекция.
|
||||
|
||||
Побеждает лучший в турнире с вероятностью p_best, иначе выбирается
|
||||
случайный участник турнира.
|
||||
"""
|
||||
size = len(population)
|
||||
selected = []
|
||||
|
||||
for _ in range(size):
|
||||
idxs = np.random.choice(size, size=k, replace=False)
|
||||
fits = fitnesses[idxs]
|
||||
order = np.argsort(-fits)
|
||||
|
||||
if np.random.random() < p_best:
|
||||
winner_idx = idxs[order[0]]
|
||||
else:
|
||||
winner_idx = np.random.choice(idxs[1:]) if k > 1 else idxs[0]
|
||||
|
||||
selected.append(population[winner_idx])
|
||||
|
||||
return selected
|
||||
|
||||
Reference in New Issue
Block a user