You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PyGAD如何实现基因无放回采样?适配座位分配约束咨询

针对骑手-座位分配问题的PyGAD适配方案

问题1:PyGAD原生支持无放回采样吗?

PyGAD不直接支持这种无放回采样的基因约束。你当前设置的gene_space会让每个基因位独立采样1-25的整数,很容易出现重复值,无法满足「每个座位仅分配给一名骑手」的核心约束。默认的初始化、交叉、变异逻辑都是基于独立基因位操作,天生不适配排列型问题。

问题2:适配无放回约束的可行方案

完全可以通过自定义PyGAD的核心算子(初始化、交叉、变异)来实现,这是PyGAD的灵活特性,不会削弱其优势,反而能精准匹配你的问题场景。具体实现如下:

1. 自定义初始化函数:生成无重复排列

每个个体对应一个1-25的随机排列(代表骑手到座位的分配),用random.sample或numpy.random.permutation实现:

import random
import pygad

def custom_initialization(num_generations, num_parents_mating, sol_per_pop, num_genes, gene_space, init_range_low, init_range_high):
    # 生成sol_per_pop个无重复的1-25排列
    population = []
    for _ in range(sol_per_pop):
        permutation = random.sample(range(1, 26), 25)
        population.append(permutation)
    return population

2. 自定义交叉算子:使用排列专用交叉算法

针对排列型问题,必须用不会产生重复值的交叉方法,推荐以下三种常用算法:

  • 部分映射交叉(PMX):最常用的排列交叉,保留父代的部分映射关系
  • 顺序交叉(OX):保留父代的基因顺序
  • 循环交叉(CX):保留父代的循环结构

以PMX为例实现自定义交叉:

def pmx_crossover(parent1, parent2):
    size = len(parent1)
    # 随机选两个交叉点
    start, end = sorted(random.sample(range(size), 2))
    # 构建映射字典
    mapping = {parent1[i]: parent2[i] for i in range(start, end)}
    mapping.update({parent2[i]: parent1[i] for i in range(start, end)})
    
    # 生成子代1
    child1 = []
    for i in range(size):
        if start <= i < end:
            child1.append(parent2[i])
        else:
            gene = parent1[i]
            while gene in mapping:
                gene = mapping[gene]
            child1.append(gene)
    
    # 生成子代2
    child2 = []
    for i in range(size):
        if start <= i < end:
            child2.append(parent1[i])
        else:
            gene = parent2[i]
            while gene in mapping:
                gene = mapping[gene]
            child2.append(gene)
    return child1, child2

3. 自定义变异算子:使用排列专用变异方法

同样要避免产生重复值,推荐以下三种:

  • 交换变异:随机交换两个位置的基因
  • 反转变异:随机选择一段区间反转基因顺序
  • 插入变异:随机选择一个基因插入到另一个位置

以交换变异为例实现:

def swap_mutation(offspring, mutation_probability):
    for i in range(len(offspring)):
        if random.random() < mutation_probability:
            # 随机选两个不同的位置
            pos1, pos2 = random.sample(range(len(offspring[i])), 2)
            # 交换基因
            offspring[i][pos1], offspring[i][pos2] = offspring[i][pos2], offspring[i][pos1]
    return offspring

4. 在PyGAD中配置自定义算子

初始化PyGAD时指定这些自定义函数:

ga_instance = pygad.GA(
    num_generations=100,
    num_parents_mating=4,
    sol_per_pop=20,
    num_genes=25,
    # 指定自定义初始化函数
    initialization_func=custom_initialization,
    # 指定自定义交叉函数
    crossover_func=pmx_crossover,
    # 指定自定义变异函数
    mutation_func=swap_mutation,
    mutation_probability=0.1,
    # 替换为你的目标函数
    fitness_func=your_fitness_function,
)

关于你提到的CDF方法

这种方法确实效率低下,因为需要额外处理重复值的过滤和调整,会增加计算开销,而且无法保证遗传算子的有效性。相比之下,直接使用排列专用的遗传算子,既能严格满足约束,又能充分利用PyGAD的框架优势,是更优的选择。

内容的提问来源于stack exchange,提问作者jbuddy_13

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 18:35:21