遗传算法个人入门笔记
先举一个简单的求解例子:
变量x,y
函数f(x,y) = (x-5)^2 + (y+3)^2 - 5
求最小值。
def test(x,y):
return (x - 5)**2 + (y - 3)**2 - 5
显然,这个函数在x=5,y=3时取最小值-5。现在我们尝试用遗传算法解决之。
遗传算法主要是模拟生物进化的过程,将每一个值视作一个生物,有自己的DNA,会发生交叉变异,同时“适者生存”。
1.编码:
规定x,y的取值范围是[-10,10],并将其映射在一个长度为12的二进制列表中:
尽管严格来说,长度为12的二进制列表最大的值为2^12-1=4095。但为了化简逆映射的求解,我们视作4096,使之可被除尽。此时x,y的取值为[-10,10)。
区间长度是20,2^12 = 4096,20/4096 = 0.0048828125。可以知道二进制数每增长1,对应的10进制数大约增长0.0048828125。
写出其编码函数:
def encode(n,n_min,n_max,dna_length):
n_range = n_max - n_min
pies= n_range / 2**dna_length
res = n - n_min
n_bit = res / pies
return get_bits_list(n_bit,dna_length)
2.解码函数:
def decode(dna,dna_length):
result = 0
for i in range(dna_length):
result += dna[i] * (2**i)
return result
将这些代码封装到一个类中:
class my_ga():
def __init__(self,n_min,n_max,dna_length):
self.n_min = n_min
self.n_max = n_max
self.dna_length = dna_length
self.n_range = self.n_max - self.n_min
self.pies= self.n_range / 2**self.dna_length
def test(x,y):
return (x - 5)**2 + (y - 3)**2 - 5
def encode(self,n):
res = n - self.n_min
n_bit = res / self.pies
print(f"n_bit is {n_bit}")
return self.get_bits_list(n_bit)
def decode(self,dna):
result = 0
for i in range(self.dna_length):
result += dna[i] * (2**i)
print(f"result now is {result}")
origin = result * self.pies + self.n_min
return origin
3.种群:
交叉与变异是建立在种群的基础上的。我们将一个(x,y)的二进制条件下的数值对视为一个个体,它们组成一个种群。先将种群数设为1000,同时,定义一个计算适应性的函数。
def get_adapt(self):
adapt = np.zeros(shape=(1000))
for i in range(1000):
adapt[i] = -self.test(self.pop_dna[i])
adapt_max = np.max(adapt)
adapt_min = np.min(adapt)
adapt_normal = (adapt-adapt_min)/(adapt_max-adapt_min) + 0.001
return adapt_normal
self.pop_dna = np.random.randint(2,size=(1000,2,dna_length))
self.adapt_normal = self.get_adapt()
接着定义根据适应性选择个体的函数:
def select(self):
idx = np.random.choice(np.arange(1000),size=(1000), replace=True, p=(self.adapt_normal)/(self.adapt_normal.sum()))
return self.pop_dna[idx]
为了让算法更灵活,我们将1000换为pop_size。
4.交叉与变异:
交叉与变异并非是必然发生的,我们需要定义一个交叉率与变异率,同时定义交叉、变异函数:
def cross(self,child):
if np.random.rand() < self.cross_rate:
mother = self.pop_dna[np.random.randint(self.pop_size)]
for j in range(2):
cross_point = np.random.randint(low=0, high=self.pop_size)
child[j][cross_point:] = mother[j][cross_point:]
return child
def muta(self,child):
if np.random.rand() < self.muta_rate:
muta_dna = np.random.randint(0,2)
muta_point = np.random.randint(0,self.pop_size)
child[muta_dna][muta_point] ^= 1
return child
def cross_muta(self):
new_pop = self.pop_dna.copy()
for i in range(self.pop_size):
new_pop[i] = self.cross(new_pop[i])
new_pop[i] = self.muta(new_pop[i])
return new_pop
输出函数:
def get_best(self):
the_min = 1e9
x = 0
y = 0
for i in range(self.pop_size):
if the_min > self.test(self.pop_dna[i]):
the_min = self.test(self.pop_dna[i])
x = self.decode(self.pop_dna[i][0])
y = self.decode(self.pop_dna[i][1])
print(f"best indiv is ({x},{y}), result is {the_min}")
测试:
ga = my_ga(n_min=-10,n_max=10,dna_length=12,pop_size=1000,cross_rate=0.8,muta_rate=0.08)
print(ga.pop_dna)
genration = 10
for _ in range(genration):
ga.cross_muta()
ga.select()
ga.get_adapt()
ga.get_best()
完整、且标准的含注释代码:
import numpy as np
class GeneticAlgorithm:
# 初始化方法,设置遗传算法的参数
def __init__(self, n_min, n_max, dna_length, pop_size, cross_rate, muta_rate):
self.n_min = n_min # 最小范围
self.n_max = n_max # 最大范围
self.dna_length = dna_length # DNA长度
self.pop_size = pop_size # 种群大小
self.cross_rate = cross_rate # 交叉概率
self.muta_rate = muta_rate # 变异概率
self.n_range = n_max - n_min # 范围差值
self.unit_interval = self.n_range / (2**dna_length) # 每个DNA单元对应的实际数值范围
self.population = np.random.randint(2, size=(pop_size, 2, dna_length)) # 随机初始化种群
self.normalized_fitness = self.calculate_fitness() # 初始化适应度
# 目标函数,需要最小化的函数
def objective_function(self, individual):
x = self.decode(individual[0]) # 解码第一个DNA片段
y = self.decode(individual[1]) # 解码第二个DNA片段
return (x - 5)**2 + (y - 3)**2 - 5 # 计算适应度值
# 将数值编码为二进制DNA片段
def encode(self, n):
res = n - self.n_min # 转换为范围内的数值
n_binary = res / self.unit_interval # 转换为二进制数
return self.to_binary_list(n_binary)
# 将二进制DNA片段解码为数值
def decode(self, dna):
result = 0
for i in range(self.dna_length):
result += dna[i] * (2**i)
decoded_value = result * self.unit_interval + self.n_min
return decoded_value
# 计算适应度值并进行归一化
def calculate_fitness(self):
fitness = np.zeros(shape=(self.pop_size)) # 初始化适应度数组
for i in range(self.pop_size):
fitness[i] = -self.objective_function(self.population[i]) # 计算适应度值
max_fitness = np.max(fitness)
min_fitness = np.min(fitness)
normalized_fitness = (fitness - 0.001 - min_fitness) / (max_fitness - min_fitness) + 0.01
self.normalized_fitness = normalized_fitness
return normalized_fitness
# 选择适应度高的个体进行繁殖
def select_population(self):
indices = np.random.choice(np.arange(self.pop_size), size=(self.pop_size), replace=True, p=(self.normalized_fitness) / (self.normalized_fitness.sum()))
self.population = self.population[indices]
# 交叉操作,生成新个体
def crossover(self, offspring):
if np.random.rand() < self.cross_rate:
parent = self.population[np.random.randint(self.pop_size)]
for j in range(2):
crossover_point = np.random.randint(low=0, high=self.dna_length)
offspring[j][crossover_point:] = parent[j][crossover_point:]
return offspring
# 变异操作
def mutate(self, offspring):
if np.random.rand() < self.muta_rate:
muta_dna = np.random.randint(0, 2)
muta_point = np.random.randint(0, self.dna_length)
offspring[muta_dna][muta_point] ^= 1
return offspring
# 对整个种群应用交叉和变异操作
def apply_crossover_and_mutation(self):
new_population = self.population.copy()
for i in range(self.pop_size):
new_population[i] = self.crossover(new_population[i])
new_population[i] = self.mutate(new_population[i])
return new_population
# 获取当前种群中最优的个体
def get_best_individual(self):
best_fitness = float('inf')
best_x, best_y = 0, 0
for i in range(self.pop_size):
current_fitness = self.objective_function(self.population[i])
if best_fitness > current_fitness:
best_fitness = current_fitness
best_x = self.decode(self.population[i][0])
best_y = self.decode(self.population[i][1])
print(f"Best individual is ({best_x}, {best_y}), fitness is {best_fitness}")
# 初始化遗传算法对象
ga = GeneticAlgorithm(n_min=-10, n_max=10, dna_length=16, pop_size=500, cross_rate=0.8, muta_rate=0.08)
generations = 10
# 迭代执行遗传算法
for _ in range(generations):
ga.apply_crossover_and_mutation()
ga.select_population()
ga.calculate_fitness()
ga.get_best_individual()
输出如下:

自此入门成功......
下一篇:用遗传算法处理2024数学建模国赛C题(咕咕咕中......)
ps:由于这个函数过于简单,并没有体现进化的过程。但我懒得改了。
这是个更显著的代码:
import numpy as np
class GeneticAlgorithm:
# 初始化方法,设置遗传算法的参数
def __init__(self, n_min, n_max, dna_length, pop_size, cross_rate, muta_rate,dna_kind_size):
self.n_min = n_min # 最小范围
self.n_max = n_max # 最大范围
self.dna_length = dna_length # DNA长度
self.pop_size = pop_size # 种群大小
self.cross_rate = cross_rate # 交叉概率
self.muta_rate = muta_rate # 变异概率
self.n_range = n_max - n_min # 范围差值
self.dna_kind_size = dna_kind_size
self.unit_interval = self.n_range / (2**dna_length) # 每个DNA单元对应的实际数值范围
self.population = np.random.randint(0, dna_kind_size, size=(pop_size, dna_kind_size, dna_length)) # 随机初始化种群
self.normalized_fitness = self.calculate_fitness() # 初始化适应度
# 目标函数,需要最小化的函数
def objective_function(self, individual):
x = self.decode(individual[0]) # 解码第一个DNA片段
y = self.decode(individual[1]) # 解码第二个DNA片段
z = self.decode(individual[2])
return -((x - 5)**2 + (y - 3)**2 + (z + 2)**2) + 5 # 计算适应度值
# 将二进制DNA片段解码为数值
def decode(self, dna):
result = 0
for i in range(self.dna_length):
result += dna[i] * (2**i)
decoded_value = result * self.unit_interval + self.n_min
return decoded_value
# 计算适应度值并进行归一化
def calculate_fitness(self):
fitness = np.zeros(shape=(self.pop_size)) # 初始化适应度数组
for i in range(self.pop_size):
fitness[i] = self.objective_function(self.population[i]) # 计算适应度值
max_fitness = np.max(fitness)
min_fitness = np.min(fitness)
normalized_fitness = (fitness - min_fitness) / (max_fitness - min_fitness + 0.00001) + 0.001
self.normalized_fitness = normalized_fitness
return normalized_fitness
# 选择适应度高的个体进行繁殖
def select_population(self):
print("normallized_fitness_sum is ",self.normalized_fitness.sum())
indices = np.random.choice(np.arange(self.pop_size), size=(self.pop_size), replace=True, p=(self.normalized_fitness) / (self.normalized_fitness.sum()))
self.population = self.population[indices]
# 交叉操作,生成新个体
def crossover(self, offspring):
if np.random.rand() < self.cross_rate:
parent = self.population[np.random.randint(self.pop_size)]
for j in range(self.dna_kind_size):
crossover_point = np.random.randint(low=0, high=self.dna_length)
offspring[j][crossover_point:] = parent[j][crossover_point:]
return offspring
# 变异操作
def mutate(self, offspring):
if np.random.rand() < self.muta_rate:
muta_dna = np.random.randint(0, self.dna_kind_size)
muta_point = np.random.randint(0, self.dna_length)
offspring[muta_dna][muta_point] ^= 1
return offspring
# 对整个种群应用交叉和变异操作
def apply_crossover_and_mutation(self):
new_population = self.population.copy()
for i in range(self.pop_size):
new_population[i] = self.crossover(new_population[i])
new_population[i] = self.mutate(new_population[i])
return new_population
# 获取当前种群中最优的个体
def get_best_individual(self):
best_fitness = float('inf')
best_x, best_y,best_z = 0, 0, 0
for i in range(self.pop_size):
current_fitness = self.objective_function(self.population[i])
if best_fitness > current_fitness:
best_fitness = current_fitness
best_x = self.decode(self.population[i][0])
best_y = self.decode(self.population[i][1])
best_z = self.decode(self.population[i][2])
print(f"Best individual is ({best_x}, {best_y}, {best_z}), fitness is {best_fitness}")
# 初始化遗传算法对象
ga = GeneticAlgorithm(n_min=-10, n_max=10, dna_length=16, pop_size=10000, cross_rate=0.8, muta_rate=0.08,dna_kind_size = 3)
generations = 50
# 迭代执行遗传算法
for _ in range(generations):
ga.apply_crossover_and_mutation()
ga.select_population()
ga.calculate_fitness()
ga.get_best_individual()

浙公网安备 33010602011771号