如何实现二进制数组解的单个基因反转突变及PyGAD参数调整
问题描述
- 需求:当解为二进制数组时,实现对单个基因的反转突变(0变1、1变0)。
- 现状:基于PyGAD编写遗传算法,设置
mutation_type="inversion"、mutation_num_genes=1,但输出不符合预期:有时无基因被修改,有时同时改变多个基因。 - 运行代码:
import pygad import numpy as np def divider(ga_instance): return np.max(np.sum(ga_instance.population, axis=1)) def on_start(ga_instance): print("on_start()") print(f'Начальная популяция:\n {ga_instance.population}') def fitness_function(ga_instance, solution, _): return np.sum(solution) / divider(ga_instance) def on_fitness(ga_instance, population_fitness): print(f'\non_fitness()') print(f'Делитель: {divider(ga_instance)}') for idx, (instance, fitness) in enumerate(zip(ga_instance.population, ga_instance.last_generation_fitness)): print(f'{idx}. {instance}: {fitness}') def on_parents(ga_instance, selected_parents): print("\non_parents()") print(f'Выбранные индексы родителей: {ga_instance.last_generation_parents_indices}') print(f'Выбранные родители:\n {ga_instance.last_generation_parents}') def on_crossover(ga_instance, offspring_crossover): print("\non_crossover()") print(f'Результат кроссинговера:\n {ga_instance.last_generation_offspring_crossover}') def on_mutation(ga_instance, offspring_mutation): print("\non_mutation()") print(f'Результат мутации:\n {ga_instance.last_generation_offspring_mutation}') def on_generation(ga_instance): print(f"\non_generation()") print("Выведенное поколение:\n ", ga_instance.population) sol = ga_instance.best_solution() print(f"Лучшее решение: {sol[0]} : {sol[1]}") ga_instance = pygad.GA( num_generations=1, num_parents_mating=2, fitness_func=fitness_function, gene_type=int, init_range_low=0, init_range_high=2, sol_per_pop=10, num_genes=8, crossover_type='single_point', parent_selection_type="rws", mutation_type="inversion", mutation_num_genes=1, on_start=on_start, on_fitness=on_fitness, on_parents=on_parents, on_crossover=on_crossover, on_mutation=on_mutation, on_generation=on_generation, ) ga_instance.run()
问题原因
PyGAD中的inversion突变类型并非指单个基因的0/1翻转,而是对一段连续基因进行逆序排列:
- 当
mutation_num_genes=1时,单个基因逆序后与原基因完全一致,因此不会产生任何变化; - 若随机选中的突变片段长度大于1,就会改变多个基因的顺序,完全偏离了你需要的单基因反转需求。
解决方案
要实现二进制基因的单基因翻转,有两种可行方案:
方案1:使用内置随机突变并限制取值范围
修改突变参数,让随机突变仅在0和1之间切换,确保每次只修改一个基因:
ga_instance = pygad.GA( # 保留原有其他参数 num_generations=1, num_parents_mating=2, fitness_func=fitness_function, gene_type=int, init_range_low=0, init_range_high=2, sol_per_pop=10, num_genes=8, crossover_type='single_point', parent_selection_type="rws", # 修改突变相关参数 mutation_type="random", mutation_num_genes=1, mutation_by_replacement=True, mutation_range=(0, 1), # 保留回调函数 on_start=on_start, on_fitness=on_fitness, on_parents=on_parents, on_crossover=on_crossover, on_mutation=on_mutation, on_generation=on_generation, )
方案2:自定义突变函数
如果需要更精准的控制,可编写自定义突变函数,确保每次仅翻转一个随机选中的二进制基因:
def custom_bit_flip_mutation(offspring, ga_instance): for idx in range(offspring.shape[0]): # 随机选择一个待翻转的基因索引 target_gene = np.random.randint(0, ga_instance.num_genes) # 执行翻转操作:0→1,1→0 offspring[idx, target_gene] = 1 - offspring[idx, target_gene] return offspring # 在GA初始化中使用自定义突变 ga_instance = pygad.GA( # 保留原有其他参数 num_generations=1, num_parents_mating=2, fitness_func=fitness_function, gene_type=int, init_range_low=0, init_range_high=2, sol_per_pop=10, num_genes=8, crossover_type='single_point', parent_selection_type="rws", # 指定自定义突变函数 mutation_type=custom_bit_flip_mutation, # 保留回调函数 on_start=on_start, on_fitness=on_fitness, on_parents=on_parents, on_crossover=on_crossover, on_mutation=on_mutation, on_generation=on_generation, )
验证效果
使用上述任意一种方案后,每次突变都会精准翻转单个二进制基因,不会出现无变化或多基因修改的情况,完全符合需求。
内容的提问来源于stack exchange,提问作者Intolighter
相关产品推荐
相关产品推荐

