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

如何在Python的DEAP中实现含多基因的基因型个体?

Got it, let's build a minimal DEAP implementation for multi-gene genotypes exactly as you described—using a tuple of numpy arrays where each gene only mates with its corresponding position, and the whole genotype contributes to fitness. We'll adapt the classic OneMax problem to fit this scenario.

Complete Working Implementation
import numpy as np
from deap import base, creator, tools, algorithms

# 1. Define fitness and individual types
creator.create("FitnessMax", base.Fitness, weights=(1.0,))
# Individual is a tuple containing numpy arrays (our multi-gene genotype)
creator.create("Individual", tuple, fitness=creator.FitnessMax)

# 2. Initialize functions for each gene and the whole individual
def init_gene1():
    # First gene: 10-length binary numpy array
    return np.random.randint(0, 2, size=10, dtype=np.int8)

def init_gene2():
    # Second gene: 42-length binary numpy array
    return np.random.randint(0, 2, size=42, dtype=np.int8)

def init_individual():
    return creator.Individual((init_gene1(), init_gene2()))

# 3. Custom crossover: cross each gene with its counterpart
def cx_two_point_multi(ind1, ind2):
    # Perform two-point crossover on each corresponding gene pair
    for i in range(len(ind1)):
        # Convert numpy arrays to lists for DEAP's built-in crossover, then convert back
        gene1_1, gene1_2 = tools.cxTwoPoint(ind1[i].tolist(), ind2[i].tolist())
        ind1[i] = np.array(gene1_1, dtype=np.int8)
        ind2[i] = np.array(gene1_2, dtype=np.int8)
    return ind1, ind2

# 4. Custom mutation: flip bits in each gene independently
def mut_flip_bit_multi(individual, indpb=0.05):
    for gene in individual:
        # Randomly select indices to flip
        flip_indices = np.random.choice(len(gene), int(len(gene)*indpb), replace=False)
        gene[flip_indices] = 1 - gene[flip_indices]
    return individual,

# 5. Fitness function: sum all 1s across both genes (OneMax for multi-gene)
def evaluate(individual):
    total_ones = np.sum(individual[0]) + np.sum(individual[1])
    return (total_ones,)

# 6. Set up the toolbox
toolbox = base.Toolbox()
toolbox.register("individual", init_individual)
toolbox.register("population", tools.initRepeat, list, toolbox.individual)
toolbox.register("mate", cx_two_point_multi)
toolbox.register("mutate", mut_flip_bit_multi, indpb=0.05)
toolbox.register("select", tools.selTournament, tournsize=3)
toolbox.register("evaluate", evaluate)

# 7. Main evolution loop
def main():
    pop = toolbox.population(n=50)
    CXPB, MUTPB, NGEN = 0.5, 0.2, 40

    # Evaluate the entire population
    fitnesses = list(map(toolbox.evaluate, pop))
    for ind, fit in zip(pop, fitnesses):
        ind.fitness.values = fit

    for g in range(NGEN):
        print(f"-- Generation {g} --")
        # Select the next generation individuals
        offspring = toolbox.select(pop, len(pop))
        # Clone the selected individuals
        offspring = list(map(toolbox.clone, offspring))

        # Apply crossover and mutation on the offspring
        for child1, child2 in zip(offspring[::2], offspring[1::2]):
            if np.random.rand() < CXPB:
                toolbox.mate(child1, child2)
                del child1.fitness.values
                del child2.fitness.values

        for mutant in offspring:
            if np.random.rand() < MUTPB:
                toolbox.mutate(mutant)
                del mutant.fitness.values

        # Evaluate the individuals with an invalid fitness
        invalid_ind = [ind for ind in offspring if not ind.fitness.valid]
        fitnesses = map(toolbox.evaluate, invalid_ind)
        for ind, fit in zip(invalid_ind, fitnesses):
            ind.fitness.values = fit

        # Replace population with offspring
        pop[:] = offspring

        # Gather all the fitnesses in one list and print the stats
        fits = [ind.fitness.values[0] for ind in pop]
        length = len(pop)
        mean = sum(fits) / length
        sum2 = sum(x*x for x in fits)
        std = abs(sum2 / length - mean**2)**0.5

        print(f"  Min {min(fits)}")
        print(f"  Max {max(fits)}")
        print(f"  Avg {mean}")
        print(f"  Std {std}")

    print("-- End of evolution --")
    best_ind = tools.selBest(pop, 1)[0]
    print(f"Best individual is {best_ind}, fitness {best_ind.fitness.values[0]}")

if __name__ == "__main__":
    main()
Key Details Explained
  • Multi-Gene Structure: We define the individual as a tuple holding two numpy arrays. This ensures each gene maintains its position throughout evolution, so we don't mix genes from different positions.
  • Position-Aware Crossover: The cx_two_point_multi function iterates over each gene pair in the individuals, applies DEAP's standard two-point crossover (converting numpy arrays to lists temporarily since DEAP's built-ins work with sequences), then converts back to numpy arrays. This guarantees only corresponding genes cross.
  • Independent Mutation: mut_flip_bit_multi applies bit-flipping mutation separately to each gene in the tuple, using numpy for efficient array operations.
  • Fitness Calculation: The evaluate function sums all 1s across both genes—just like the classic OneMax problem, but using the entire multi-gene genotype.
  • Toolbox Configuration: We register our custom operators instead of DEAP's defaults, so the framework uses our position-aware logic for crossover and mutation.

内容的提问来源于stack exchange,提问作者Josh.F

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 08:00:48