基于定长实数向量的遗传算法实现:编码与初始化疑问
问题描述
我正尝试实现基于定长实数向量的遗传算法(Genetic Algorithm),目前找到一个采用二进制编码的简易Python实现,但在数组初始化与算法边界设置上存在困惑。以下是原代码中的二进制解码片段:
def decode(bounds, n_bits, bitstring): decoded = list() largest = 2**n_bits for i in range(len(bounds)): # extract the substring start, end = i * n_bits, (i * n_bits)+n_bits substring = bitstring[start:end] # convert bitstring to a string of chars chars = ''.join([str(s) for s in substring]) # convert string to integer integer = int(chars, 2) # scale integer to desired range value = bounds[i][0] + (integer/largest) * (bounds[i][1] - bounds[i][0]) # store decoded.append(value) return decoded
请问能否将其改写为用实数数组而非比特串来编码解的形式?完整代码来自文章《Simple Genetic Algorithm From Scratch in Python》,完整代码如下:
# genetic algorithm search for continuous function optimization from numpy.random import randint from numpy.random import rand # objective function def objective(x): return x[0] ** 2.0 + x[1] ** 2.0 # decode bitstring to numbers def decode(bounds, n_bits, bitstring): decoded = list() largest = 2 ** n_bits for i in range(len(bounds)): # extract the substring start, end = i * n_bits, (i * n_bits) + n_bits substring = bitstring[start:end] # convert bitstring to a string of chars chars = ''.join([str(s) for s in substring]) # convert string to integer integer = int(chars, 2) # scale integer to desired range value = bounds[i][0] + (integer / largest) * (bounds[i][1] - bounds[i][0]) # store decoded.append(value) return decoded # tournament selection def selection(pop, scores, k=3): # first random selection selection_ix = randint(len(pop)) for ix in randint(0, len(pop), k - 1): # check if better (e.g. perform a tournament) if scores[ix] < scores[selection_ix]: selection_ix = ix return pop[selection_ix] # crossover two parents to create two children def crossover(p1, p2, r_cross): # children are copies of parents by default c1, c2 = p1.copy(), p2.copy() # check for recombination if rand() < r_cross: # select crossover point that is not on the end of the string pt = randint(1, len(p1) - 2) # perform crossover c1 = p1[:pt] + p2[pt:] c2 = p2[:pt] + p1[pt:] return [c1, c2] # mutation operator def mutation(bitstring, r_mut): for i in range(len(bitstring)): # check for a mutation if rand() < r_mut: # flip the bit bitstring[i] = 1 - bitstring[i] # genetic algorithm def genetic_algorithm(objective, bounds, n_bits, n_iter, n_pop, r_cross, r_mut): # initial population of random bitstring pop = [randint(0, 2, n_bits * len(bounds)).tolist() for _ in range(n_pop)] # keep track of best solution best, best_eval = 0, objective(decode(bounds, n_bits, pop[0])) # enumerate generations for gen in range(n_iter): # decode population decoded = [decode(bounds, n_bits, p) for p in pop] # evaluate all candidates in the population scores = [objective(d) for d in decoded] # check for new best solution for i in range(n_pop): if scores[i] < best_eval: best, best_eval = pop[i], scores[i] print(">%d, new best f(%s) = %f" % (gen, decoded[i], scores[i])) # select parents selected = [selection(pop, scores) for _ in range(n_pop)] # create the next generation children = list() for i in range(0, n_pop, 2): # get selected parents in pairs p1, p2 = selected[i], selected[i + 1] # crossover and mutation for c in crossover(p1, p2, r_cross): # mutation mutation(c, r_mut) # store for next generation children.append(c) # replace population pop = children return [best, best_eval] # define range for input bounds = [[-5.0, 5.0], [-5.0, 5.0]] # define the total iterations n_iter = 100 # bits per variable n_bits = 16 # define the population size n_pop = 100 # crossover rate r_cross = 0.9 # mutation rate r_mut = 1.0 / (float(n_bits) * len(bounds)) # perform the genetic algorithm search best, score = genetic_algorithm(objective, bounds, n_bits, n_iter, n_pop, r_cross, r_mut) print('Done!') decoded = decode(bounds, n_bits, best) print('f(%s) = %f' % (decoded, score))
改写后的实数编码遗传算法实现
当然可以直接用实数数组编码解,这样就不需要解码步骤,直接对实数向量进行选择、交叉、突变操作即可。以下是改写后的完整代码:
# 实数编码的遗传算法:连续函数优化 from numpy.random import rand from numpy.random import randint # 目标函数(以二元二次函数为例) def objective(x): return x[0] ** 2.0 + x[1] ** 2.0 # 锦标赛选择 def selection(pop, scores, k=3): # 随机选择第一个候选者 selection_ix = randint(len(pop)) for ix in randint(0, len(pop), k - 1): # 锦标赛比较,保留更优解(这里是最小化问题) if scores[ix] < scores[selection_ix]: selection_ix = ix return pop[selection_ix] # 实数交叉:模拟二进制交叉(SBX),适合连续变量 def crossover(p1, p2, bounds, r_cross): c1, c2 = p1.copy(), p2.copy() if rand() < r_cross: for i in range(len(p1)): # 生成0-1之间的随机数 u = rand() if u <= 0.5: beta = (2 * u) ** (1 / (3 + 1)) # 分布指数设为3,可调整 else: beta = (1 / (2 * (1 - u))) ** (1 / (3 + 1)) # 计算交叉后的子代值 c1[i] = 0.5 * ((1 + beta) * p1[i] + (1 - beta) * p2[i]) c2[i] = 0.5 * ((1 - beta) * p1[i] + (1 + beta) * p2[i]) # 确保值在边界范围内 c1[i] = max(bounds[i][0], min(c1[i], bounds[i][1])) c2[i] = max(bounds[i][0], min(c2[i], bounds[i][1])) return [c1, c2] # 实数突变:高斯突变 def mutation(individual, bounds, r_mut): for i in range(len(individual)): if rand() < r_mut: # 生成高斯分布的突变值,均值为当前值,标准差设为范围的10% sigma = (bounds[i][1] - bounds[i][0]) * 0.1 mutated = individual[i] + rand() * sigma * 2 - sigma # 确保突变后的值在边界内 individual[i] = max(bounds[i][0], min(mutated, bounds[i][1])) # 遗传算法主函数 def genetic_algorithm(objective, bounds, n_iter, n_pop, r_cross, r_mut): # 初始化种群:直接生成符合边界的实数向量 pop = [[bounds[i][0] + rand() * (bounds[i][1] - bounds[i][0]) for i in range(len(bounds))] for _ in range(n_pop)] # 跟踪最优解 best, best_eval = pop[0], objective(pop[0]) # 迭代进化 for gen in range(n_iter): # 评估所有个体 scores = [objective(ind) for ind in pop] # 更新最优解 for i in range(n_pop): if scores[i] < best_eval: best, best_eval = pop[i], scores[i] print(f">第{gen}代,找到新最优解 f({best}) = {best_eval:.6f}") # 选择父代 selected = [selection(pop, scores) for _ in range(n_pop)] # 生成子代 children = [] for i in range(0, n_pop, 2): p1, p2 = selected[i], selected[i+1] # 交叉 for c in crossover(p1, p2, bounds, r_cross): # 突变 mutation(c, bounds, r_mut) children.append(c) # 替换种群 pop = children return [best, best_eval] # 配置参数 bounds = [[-5.0, 5.0], [-5.0, 5.0]] # 变量范围 n_iter = 100 # 迭代代数 n_pop = 100 # 种群大小 r_cross = 0.9 # 交叉概率 r_mut = 1.0 / len(bounds) # 突变概率(每个变量的突变概率) # 运行遗传算法 best, score = genetic_algorithm(objective, bounds, n_iter, n_pop, r_cross, r_mut) print('计算完成!') print(f'最优解 f({best}) = {score:.6f}')
关键改动说明
- 种群初始化:直接在
bounds定义的范围内生成随机实数向量,无需二进制编码和解码步骤,简化流程。 - 交叉操作:使用模拟二进制交叉(SBX),这是针对连续变量设计的交叉方式,能保持解的连续性和多样性,替代原代码的位交叉。
- 突变操作:采用高斯突变,在当前个体值附近生成符合高斯分布的突变值,同时确保结果不超出边界,替代原代码的位翻转。
- 去掉解码步骤:所有操作直接针对实数向量,评估时无需解码,效率更高。
内容的提问来源于stack exchange,提问作者No_Name
相关产品推荐
相关产品推荐

