1. 简介
遗传算法是一种基于生物进化原理而产生的计算方法,是一种搜索算法,目标是从一组解中找到能够最大化或最小化某个特定目标函数的解。其思想是模拟达尔文进化论中的自然选择和遗传机制,根据每个个体的适应度来选择优秀的个体,然后通过交叉互换和变异等操作筛选出更好的个体,并不断地迭代以求得最优解。
本文将介绍如何使用Python实现简单遗传算法,主要包括以下几个部分:目标函数的定义、参数设置、种群初始化、适应度函数的编写、选择操作、交叉互换和变异等。
2. 目标函数的定义
在本例中,我们选用经典的函数y=sin(10x)+x,其中取值范围为0到1,目标是通过遗传算法来寻找使得函数值最大的x.
import math
def fitness(x):
y = math.sin(10 * x) + x
return y
其中fitness函数即为我们所定义的目标函数,输入的x即为待求解的变量值。
3. 参数设置
以下是一些关键参数的设置:
population_size:种群的大小,即个体的数量
chromosome_length:染色体的长度,即每个个体的基因数量
crossover_rate:交叉概率,即两个个体进行交叉的概率
mutation_rate:变异概率,即某个个体发生变异的概率
max_generation:最大迭代次数
temperature:初始化选举温度
population_size = 100 # 种群大小,即个体数量
chromosome_length = 20 # 染色体长度,即每个个体基因数量
crossover_rate = 0.8 # 交叉概率,两个个体进行交叉的概率
mutation_rate = 0.01 # 变异概率,某个个体发生变异的概率
max_generation = 200 # 最大迭代次数
temperature = 0.6 # 初始化选举温度
4. 种群初始化
种群的初始化是遗传算法的第一步,其目的是产生一组符合要求的个体集合。在本例中,我们采用二进制编码的方式来表示每个个体的基因,即将范围在(0, 1)之间的x值转换为20位二进制数的形式,这样每个个体就可以用一个长度为20的字符串表示。种群初始化的代码如下:
import random
def init_population():
population = []
for i in range(population_size):
chromosome = ''
for j in range(chromosome_length):
chromosome += str(random.randint(0, 1))
population.append(chromosome)
return population
其中,init_population函数即为我们所定义的种群初始化函数,该函数返回一个由多个个体组成的列表population,其中每个个体均为长度为20的二进制字符串。
5. 适应度函数的编写
适应度函数的作用是计算个体的适应度值,以此作为选择、交叉和变异的依据。在本例中,我们使用fitness函数来计算每个个体的适应度值,即y值。但是,由于我们的目标是求函数最大值,而在遗传算法中通常使用最小化函数,因此有必要将fitness函数进行一定的转换。
def adapt(population):
fitnesses = []
for i in range(len(population)):
individual = population[i]
x = int(individual, 2) / (2 ** chromosome_length - 1) # 将二进制转换为实数
fitnesses.append(1 / float(fitness(x))) # 将最大化函数转换为最小化函数
total_fitness = sum(fitnesses)
adapt_values = [fitnesses[i] / total_fitness for i in range(len(population))] # 计算适应度值
return adapt_values
其中adapt函数即为我们所定义的适应度函数,该函数接受种群population作为输入,返回一个适应度值的列表adapt_values。该函数首先将二进制字符串转换为实数,然后计算其对应的适应度值,将最大化函数转化为最小化函数。最后,该函数计算每个个体的适应度值,并将其标准化。
6. 选择操作
选择操作的目的是从种群中选择出适应度最高的个体,用于交叉和变异。在本文中,我们采用轮盘赌选择算法来进行个体的挑选。具体来说,轮盘赌选择算法的过程如下:
计算每个个体的适应度值
计算每个个体被选中的概率
根据轮盘赌法规则进行选择(即按照适应度值的大小确定各自所占的权重,并使用随机数在所有个体中选择一个个体)
def select(population, adapt_values):
new_population = []
for i in range(len(population)):
cumsum_adapt_values = [sum(adapt_values[:i + 1]) for i in range(len(population))] # 计算累计适应度值
pointer = random.uniform(0, 1) # 生成一个随机数
for i in range(len(population)):
if pointer < cumsum_adapt_values[i]:
new_population.append(population[i])
break
return new_population
其中select函数即为我们所定义的选择函数,该函数接受种群population和相应的适应度值列表adapt_values为输入,返回一个选择过后的新种群new_population。该函数首先计算每个个体的累计适应度值,然后生成一个随机数,并按照轮盘赌法规则进行选择,最后将选择过后的新个体加入到新种群new_population中。
7. 交叉互换
交叉互换的目的是通过交叉互换来产生新的个体,从而保证种群的多样性。在本例中,我们采用单点交叉的方式进行个体的交换。具体来说,单点交叉的过程如下:
从种群中选中两个个体
根据交叉概率,决定是否对这两个个体进行交叉
从两个个体中随机选取一个交叉点
将两个个体在交叉点处的染色体进行交换
def crossover(population):
for i in range(len(population) - 1):
if random.uniform(0, 1) < crossover_rate:
cross_point = random.randint(1, chromosome_length - 1) # 随机选择交叉点
chrom_a = population[i][:cross_point] + population[i + 1][cross_point:]
chrom_b = population[i + 1][:cross_point] + population[i][cross_point:]
population[i], population[i + 1] = chrom_a, chrom_b
return population
其中crossover函数即为我们所定义的交叉互换函数,该函数接受种群population为输入,返回一个交叉互换过后的种群。该函数首先从种群中随机选择两个个体,并按照交叉概率决定是否进行交叉操作,然后随机选择交叉点,将两个个体在交叉点处的染色体进行交换。
8. 变异操作
变异操作的目的是通过变异来产生新的个体,并保证种群的多样性。在本例中,我们采用单点变异的方式进行个体的变异。具体来说,单点变异的过程如下:
从种群中选中一个个体
根据变异概率,决定是否对这个个体进行变异
从这个个体中随机选取一个基因
将这个基因进行取反操作
def mutation(population):
for i in range(len(population)):
if random.uniform(0, 1) < mutation_rate:
mutation_point = random.randint(0, chromosome_length - 1) # 随机选择变异点
mutation_bit = population[i][mutation_point]
new_bit = '0' if mutation_bit == '1' else '1'
population[i] = population[i][:mutation_point] + new_bit + population[i][mutation_point + 1:]
return population
其中mutation函数即为我们所定义的变异函数,该函数接受种群population为输入,返回一个进行变异操作过后的种群。该函数首先从种群中随机选择一个个体,并按照变异概率决定是否进行变异操作,然后随机选择变异点,将这个基因进行取反操作。
9. 完整代码
下面是完整代码的实现:
import math
import random
population_size = 100 # 种群大小,即个体数量
chromosome_length = 20 # 染色体长度,即每个个体基因数量
crossover_rate = 0.8 # 交叉概率,两个个体进行交叉的概率
mutation_rate = 0.01 # 变异概率,某个个体发生变异的概率
max_generation = 200 # 最大迭代次数
temperature = 0.6 # 初始化选举温度
def fitness(x):
y = math.sin(10 * x) + x
return y
def init_population():
population = []
for i in range(population_size):
chromosome = ''
for j in range(chromosome_length):
chromosome += str(random.randint(0, 1))
population.append(chromosome)
return population
def adapt(population):
fitnesses = []
for i in range(len(population)):
individual = population[i]
x = int(individual, 2) / (2 ** chromosome_length - 1) # 将二进制转换为实数
fitnesses.append(1 / float(fitness(x))) # 将最大化函数转换为最小化函数
total_fitness = sum(fitnesses)
adapt_values = [fitnesses[i] / total_fitness for i in range(len(population))] # 计算适应度值
return adapt_values
def select(population, adapt_values):
new_population = []
for i in range(len(population)):
cumsum_adapt_values = [sum(adapt_values[:i + 1]) for i in range(len(population))] # 计算累计适应度值
pointer = random.uniform(0, 1) # 生成一个随机数
for i in range(len(population)):
if pointer < cumsum_adapt_values[i]:
new_population.append(population[i])
break
return new_population
def crossover(population):
for i in range(len(population) - 1):
if random.uniform(0, 1) < crossover_rate:
cross_point = random.randint(1, chromosome_length - 1) # 随机选择交叉点
chrom_a = population[i][:cross_point] + population[i + 1][cross_point:]
chrom_b = population[i + 1][:cross_point] + population[i][cross_point:]
population[i], population[i + 1] = chrom_a, chrom_b
return population
def mutation(population):
for i in range(len(population)):
if random.uniform(0, 1) < mutation_rate:
mutation_point = random.randint(0, chromosome_length - 1) # 随机选择变异点
mutation_bit = population[i][mutation_point]
new_bit = '0' if mutation_bit == '1' else '1'
population[i] = population[i][:mutation_point] + new_bit + population[i][mutation_point + 1:]
return population
if __name__ == '__main__':
population = init_population()
best_individual = population[0]
g = 0
while True:
adapt_values = adapt(population)
new_population = select(population, adapt_values)
new_population = crossover(new_population)
new_population = mutation(new_population)
population = new_population
g += 1
# 更新最优个体
for i in range(len(population)):
if fitness(int(population[i], 2)) > fitness(int(best_individual, 2)):
best_individual = population[i]
if g > max_generation:
break
print('The best individual is:', best_individual)
print('The best fitness is:', fitness(int(best_individual, 2)))
10. 总结
本文介绍了如何使用Python实现简单遗传算法,并以求函数最大值为例进行了演示。遗传算法作为一种优化算法,可以在复杂问题中快速找到最优解。在实现遗传算法时,我们需要考虑到一些关键参数的设置,包括种群大小、染色体长度、交叉互换和变异等操作的概率等等。在实际应用过程中,我们还需要结合具体问题进行调参和分析,以获得更好的优化结果。