DEAP遗传算法参数越界与类型异常问题求助
Hey there! I see you're new to DEAP and ran into two key issues with your optimization script: integer parameters turning into floats after mutation, and parameters drifting outside your defined MIN/MAX bounds. Let's fix these problems with targeted changes to your code.
The Root Causes
- Type Loss: Using
mutGaussianon the entire individual affects your integer parameter—Gaussian mutation adds floating-point values, turning your int into a float. - Boundary Drift: DEAP's default operators don't enforce bounds post-initialization, so crossover/mutation can push parameters outside your
MIN_X/MAX_Xranges.
Step-by-Step Fixes
1. Custom Mutation Function
We need to handle integer and float parameters separately to preserve types and bounds. Create a custom mutation function that uses integer-specific mutation for your int parameter, and constrained Gaussian mutation for your float parameter:
def custom_mutate(individual): # Mutate integer parameter (first element) within its bounds tools.mutUniformInt(individual, low=MIN_2, up=MAX_2, indpb=0.2) # Mutate float parameter (second element) tools.mutGaussian(individual, mu=0, sigma=1, indpb=0.2) # Enforce integer type and bounds for the first parameter individual[0] = max(MIN_2, min(MAX_2, int(round(individual[0])))) # Enforce bounds for the float parameter individual[1] = max(MIN_1, min(MAX_1, individual[1])) return individual,
2. Update Toolbox Registration
Replace your default mutation registration with our custom function:
# Replace this line: # toolbox.register("mutate", tools.mutGaussian, mu=0, sigma=1, indpb=0.2) # With this: toolbox.register("mutate", custom_mutate)
3. (Optional) Add Post-Crossover Bound Check
While cxTwoPoint won't change types here (since it swaps like-positioned elements), you can add a quick check to ensure bounds are maintained after crossover if needed. Add this inside your crossover loop:
if random.random() < CXPB: toolbox.mate(child1, child2) # Post-crossover bound enforcement child1[0] = max(MIN_2, min(MAX_2, child1[0])) child1[1] = max(MIN_1, min(MAX_1, child1[1])) child2[0] = max(MIN_2, min(MAX_2, child2[0])) child2[1] = max(MIN_1, min(MAX_1, child2[1])) del child1.fitness.values del child2.fitness.values
Full Modified Script
Here's your complete script with all fixes applied:
import random from deap import base from deap import creator from deap import tools CXPB, MUTPB = 0.2, 0.2 IND_SIZE = 1 POP_SIZE = 10 GEN_SIZE = 50 MIN_1, MAX_1 = 7.5, 8.5 MIN_2, MAX_2 = 20, 60 creator.create("FitnessMin", base.Fitness, weights=(-1.0, -1.0)) creator.create("Individual", list, fitness=creator.FitnessMin) toolbox = base.Toolbox() toolbox.register("attr_float", random.uniform, MIN_1, MAX_1) toolbox.register("attr_int" , random.randint, MIN_2, MAX_2) toolbox.register("individual", tools.initCycle, creator.Individual,(toolbox.attr_int,toolbox.attr_float), IND_SIZE) toolbox.register("population", tools.initRepeat, list, toolbox.individual) toolbox.register("mate", tools.cxTwoPoint) # Custom mutation function to handle mixed types and bounds def custom_mutate(individual): tools.mutUniformInt(individual, low=MIN_2, up=MAX_2, indpb=0.2) tools.mutGaussian(individual, mu=0, sigma=1, indpb=0.2) # Enforce integer type and bounds individual[0] = max(MIN_2, min(MAX_2, int(round(individual[0])))) # Enforce float bounds individual[1] = max(MIN_1, min(MAX_1, individual[1])) return individual, toolbox.register("mutate", custom_mutate) toolbox.register("select", tools.selTournament, tournsize=3) def evaluate(individual): print ('evaluate:',individual) a = sum(individual) b = len(individual) return a, 1. / b toolbox.register("evaluate", evaluate) pop = toolbox.population(n=POP_SIZE) for g in range(GEN_SIZE): print ('generation',g) # Select the next generation individuals offspring = toolbox.select(pop, len(pop)) # Clone the selected individuals (convert map to list for Python 3 compatibility) offspring = list(map(toolbox.clone, offspring)) # Apply crossover on the offspring for child1, child2 in zip(offspring[::2], offspring[1::2]): if random.random() < CXPB: toolbox.mate(child1, child2) # Optional post-crossover bound check child1[0] = max(MIN_2, min(MAX_2, child1[0])) child1[1] = max(MIN_1, min(MAX_1, child1[1])) child2[0] = max(MIN_2, min(MAX_2, child2[0])) child2[1] = max(MIN_1, min(MAX_1, child2[1])) del child1.fitness.values del child2.fitness.values # Apply mutation on the offspring for mutant in offspring: if random.random() < 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 = toolbox.map(toolbox.evaluate, invalid_ind) for ind, fit in zip(invalid_ind, fitnesses): ind.fitness.values = fit # The population is entirely replaced by the offspring pop[:] = offspring
Key Notes
- Integer Preservation: Using
mutUniformIntfor the integer parameter ensures it stays within bounds and maintains integer type. We also add aroundandintconversion as a safety net. - Boundary Enforcement: The
max(MIN, min(MAX, value))pattern clamps parameters to your defined ranges—no more values outside7.5-8.5or20-60. - Python 3 Compatibility: Converted the
mapresult to a list to avoid iteration issues in Python 3.
内容的提问来源于stack exchange,提问作者user3884301




