如何在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_multifunction 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_multiapplies bit-flipping mutation separately to each gene in the tuple, using numpy for efficient array operations. - Fitness Calculation: The
evaluatefunction 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
相关产品推荐
相关产品推荐

