首先先附上代码的全部内容再对代码进行一一解析
import random
import string
# 目标字符串
target_string = "HELLO, WORLD!"
# 参数设置
population_size = 500
mutation_rate = 0.3
generations = 11000
def generate_random_string(length):
return ''.join(random.choice(string.printable) for _ in range(length))
def calculate_fitness(individual):
return sum(1 for a, b in zip(individual, target_string) if a == b)
def crossover(parent1, parent2):
# 一点交叉
crossover_point = random.randint(0, len(parent1) - 1)
child = parent1[:crossover_point] + parent2[crossover_point:]
return child
def mutate(individual):
# 随机选择一个位置进行变异
mutation_point = random.randint(0, len(individual) - 1)
mutated_char = random.choice(string.printable)
return individual[:mutation_point] + mutated_char + individual[mutation_point + 1:]
def genetic_algorithm():
# 初始化种群
population = [generate_random_string(len(target_string)) for _ in range(population_size)]
for generation in range(generations):
# 计算适应度
fitness_scores = [calculate_fitness(individual) for individual in population]
# 找到当前最优解
best_individual = population[fitness_scores.index(max(fitness_scores))]
print(f"Generation {generation + 1}: {best_individual} (Fitness: {max(fitness_scores)})")
# 如果找到完美解决方案,退出循环
if max(fitness_scores) == len(target_string):
break
# 选择父代
selected_parents = random.choices(population, weights=fitness_scores, k=2)
# 交叉产生新个体
child = crossover(selected_parents[0], selected_parents[1])
# 变异
if random.random() < mutation_rate:
child = mutate(child)
# 替换旧个体
population[random.randint(0, population_size - 1)] = child
# 打印每一步的种群
print("Population:", population)
print("Algorithm finished.")
print("Best solution:", best_individual)
# 运行遗传算法
genetic_algorithm()
运行结果
参数设置
# 参数设置
population_size = 500
mutation_rate = 0.3
generations = 11000
-
种群大小 (
种群大小是指每一代中包含的个体数量。在这个遗传算法中,种群大小被设置为 500。较大的种群大小通常能够更好地覆盖搜索空间,但也需要更多的计算资源。这个值的选择应根据问题的复杂性和可用的计算资源来确定。population_size
): -
变异率 (
变异率表示在交叉操作后,每个个体发生变异的概率。在这里,变异率被设置为 0.3,即30%的概率。较高的变异率可以帮助算法跳出局部最优解,但过高的变异率可能导致搜索过于随机。这个值的选择取决于对搜索过程的探索程度的期望。mutation_rate
): -
迭代的代数 (
代数数表示算法将运行的总次数。在这个例子中,迭代的代数被设置为 11000。这个值的选择通常需要考虑算法运行的时间和是否能在给定的代数内找到满足条件的解。如果在指定的代数内找到了满足条件的解,算法将提前结束。generations
):
生产随机字符函数
def generate_random_string(length):
return ''.join(random.choice(string.printable) for _ in range(length)
-
random.choice(string.printable)
:random.choice
函数用于从给定的可迭代对象中随机选择一个元素。- 在这里,
string.printable
是一个包含所有可打印ASCII字符的字符串,包括数字、字母、标点符号和空格。 - 因此,
random.choice(string.printable)
会在这些字符中随机选择一个字符。
-
for _ in range(length)
:- 使用
for
循环迭代range(length)
,生成指定长度的字符。
- 使用
-
''.join(...)
:join
方法用于将可迭代对象的元素连接成一个字符串。- 在这里,将
random.choice(string.printable)
在循环中生成的字符连接成一个字符串。
-
return ...
:- 返回由随机选择的字符组成的字符串。
因此,这个函数的作用是生成一个具有指定长度的随机字符串,该字符串的字符来自于所有可打印ASCII字符
适应度函数
def calculate_fitness(individual):
return sum(1 for a, b in zip(individual, target_string) if a == b)
-
zip(individual, target_string)
:zip
函数接受两个可迭代对象,将它们的元素逐一配对。在这里,它将individual
和target_string
中的字符一一配对,生成一个迭代器。- 例如,如果
individual
是 "ABC",而target_string
是 "ADE",那么zip
将生成迭代器:('A', 'A'), ('B', 'D'), ('C', 'E')
。
-
(1 for a, b in ...)
:- 这是一个生成器表达式。它遍历
zip
生成的配对,对于每一对(a, b)
,生成一个值为1
的元素。 - 如果在对应的位置上
individual
和target_string
中的字符相等,则生成的值是1
,否则是0
。
- 这是一个生成器表达式。它遍历
-
if a == b
:- 过滤条件。只有在
individual
和target_string
中的字符相等时才生成1
。
- 过滤条件。只有在
-
sum(...)
:sum
函数对生成器表达式生成的值进行求和,即计算匹配的字符数量。
所以,整个语句的含义是:对于两个字符串 individual
和 target_string
中相应位置上相等的字符,计算它们的数量。进而用于遗传算法中的适应度计算。下面通过具体例子说明代码
假设目标字符串是 "HELLO, WORLD!",而个体字符串是 "HELLO, PEOPLE!"
zip(individual, target_string)
:
- 对应位置的字符配对为:
('H', 'H'), ('E', 'E'), ('L', 'L'), ('L', 'L'), ('O', 'O'), (',', ','), (' ', ' '), ('W', 'W'), ('O', 'O'), ('R', 'R'), ('L', 'L'), ('D', 'D'), ('!', '!')
(1 for a, b in ...)
:
- 由于个体字符和目标字符在每个位置上都匹配,生成的元素为
1
。
sum(...)
:
- 对生成的
1
进行求和,得到总和:1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 = 13
return sum(1 for a, b in zip(individual, target_string) if a == b)
:
- 返回适应度分数
13
。
交叉函数
def crossover(parent1, parent2):
# 一点交叉
crossover_point = random.randint(0, len(parent1) - 1)
child = parent1[:crossover_point] + parent2[crossover_point:]
return child
-
rossover_point = random.randint(0, len(parent1) - 1)
:- 随机选择一个交叉点,这个点将决定在哪里进行交叉。它在父代个体的基因序列中的位置。
-
child = parent1[:crossover_point] + parent2[crossover_point:]
:parent1[:crossover_point]
取parent1
的基因序列的开头到交叉点之前的部分。parent2[crossover_point:]
取parent2
的基因序列从交叉点开始到末尾的部分。- 这两部分被连接起来,形成了新个体(子代)的基因序列。
-
return child
:- 返回表示子代的基因序列。
这个交叉过程模拟了生物遗传中的杂交过程,其中从两个父代中选择某个点,然后将其前半部分与后半部分组合以产生新个体,其实就是拼凑了两个个体中的一部分。这有助于保留父代中较好的特征,并且在不同个体之间引入差异性。
变异函数
def mutate(individual):
# 随机选择一个位置进行变异
mutation_point = random.randint(0, len(individual) - 1)
mutated_char = random.choice(string.printable)
return individual[:mutation_point] + mutated_char + individual[mutation_point + 1:]
-
random.randint(0, len(individual) - 1)
:random.randint
是random
模块中的函数,用于生成指定范围内的随机整数。- 这里它生成一个在 0 和
len(individual) - 1
之间的随机整数,即变异点的位置。
-
random.choice(string.printable)
:random.choice
函数用于从给定的可迭代对象中随机选择一个元素。- 在这里,它从
string.printable
中随机选择一个字符。这个字符串包含了所有可打印ASCII字符。
-
mutated_char = random.choice(string.printable)
:- 选择的随机字符用于代替变异点处的原始字符。
-
individual[:mutation_point] + mutated_char + individual[mutation_point + 1:]
:- 切片操作被用来构建一个新的基因序列。
individual[:mutation_point]
返回变异点之前的部分。mutated_char
是变异点处的新字符。individual[mutation_point + 1:]
返回变异点之后的部分。- 这三部分被连接起来形成一个新的基因序列,即发生了变异的个体。
-
return individual[:mutation_point] + mutated_char + individual[mutation_point + 1:]
:- 返回表示发生变异的个体的新基因序列。
这个函数通过在基因序列中的一个随机位置引入变异,用新的随机字符替代原始字符。
遗传算法函数
def genetic_algorithm():
# 初始化种群
population = [generate_random_string(len(target_string)) for _ in range(population_size)]
for generation in range(generations):
# 计算适应度
fitness_scores = [calculate_fitness(individual) for individual in population]
# 找到当前最优解
best_individual = population[fitness_scores.index(max(fitness_scores))]
print(f"Generation {generation + 1}: {best_individual} (Fitness: {max(fitness_scores)})")
# 如果找到完美解决方案,退出循环
if max(fitness_scores) == len(target_string):
break
# 选择父代
selected_parents = random.choices(population, weights=fitness_scores, k=2)
# 交叉产生新个体
child = crossover(selected_parents[0], selected_parents[1])
# 变异
if random.random() < mutation_rate:
child = mutate(child)
# 替换旧个体
population[random.randint(0, population_size - 1)] = child
# 打印每一步的种群
print("Population:", population)
print("Algorithm finished.")
print("Best solution:", best_individual)
-
使用列表推导式初始化一个由随机字符串组成的种群。每个字符串的长度与目标字符串相同。population = [generate_random_string(len(target_string)) for _ in range(population_size)]
: -
外部循环,迭代代数。for generation in range(generations):
: -
计算每个个体的适应度分数,将结果存储在列表fitness_scores = [calculate_fitness(individual) for individual in population]
:fitness_scores
中。 -
找到当前代种群中适应度最高的个体。best_individual = population[fitness_scores.index(max(fitness_scores))]
: -
打印当前代数、最佳个体及其适应度分数。print(f"Generation {generation + 1}: {best_individual} (Fitness: {max(fitness_scores)})")
: -
如果找到完美解决方案,退出循环。if max(fitness_scores) == len(target_string):
: -
选择两个父代个体,概率权重与它们的适应度分数成正比。selected_parents = random.choices(population, weights=fitness_scores, k=2)
: -
通过交叉操作产生一个新的子代。child = crossover(selected_parents[0], selected_parents[1])
: -
根据变异率的概率决定是否进行变异。if random.random() < mutation_rate:
: -
如果进行变异,对子代进行变异操作。child = mutate(child)
: -
用新的子代替换原种群中的一个个体。population[random.randint(0, population_size - 1)] = child
: