利用遗传算法求函数极值
引入numpy库
import numpy as np
定义相关参数:种群数量、交叉概率、变异概率、自变量的范围、DNA长度(一般=10)、循环代数
pop_size = 100 # 种群数量
PC=0.8 # 交叉概率
PM=0.01 #变异概率
X_max=2 #最大值
X_min=-1 #最小值
DNA_SIZE=10 #DNA长度与保留位数有关,2**10 当前保留3位小数点
N_GENERATIONS=1000 #循环代数
目标函数
def aim(x):
return x*np.sin(10*np.pi*x)+1.0
生成二进制编码
pop = np.random.randint(2, size=(pop_size, DNA_SIZE))
解码
def decode(pop):
return pop.dot(2 ** np.arange(DNA_SIZE)[::-1]) *(X_max-X_min)/ float(2**DNA_SIZE-1) +X_min
适应度:求最大值可以用原值作为适应度,为了防止产生0和负数加上一个偏移 1e-3 - np.min(pred)
def fitnessget(pred):
return pred + 1e-3 - np.min(pred)
选择
numpy.random.choice(a, size=None, replace=True, p=None)
从a(只要是ndarray都可以,但必须是一维的)中随机抽取数字,并组成指定大小(size)的数组
replace:True表示可以取相同数字,False表示不可以取相同数字
数组p:与数组a相对应,表示取数组a中每个元素的概率,默认为选取每个元素的概率相同。
def select(pop, fitness):
idx = np.random.choice(np.arange(pop_size), size=pop_size, replace=True,p=fitness/fitness.sum())
return pop[idx]
交叉
np.astype() 转换numpy数组的数据类型
def change(parent, pop):
if np.random.rand() < PC: #交叉概率
i_ = np.random.randint(0, pop_size, size=1)
cross_points = np.random.randint(0, 2, size=DNA_SIZE).astype(bool)
parent[cross_points] = pop[i_, cross_points]
return parent
变异
def variation(child,pm):
for point in range(DNA_SIZE):
if np.random.rand() < pm: #变异概率
child[point] = 1 if child[point] == 0 else 0
return child
循环迭代
for i in range(N_GENERATIONS):
#解码
X_value= decode(pop)
#获取目标函数值
F_values = aim(X_value)
#获取适应值
fitness = fitnessget(F_values)
#开始,max=F_values最大的
if(i==0):
max=np.max(F_values)
max_DNA = pop[np.argmax(F_values)]
if(max<np.max(F_values)):
max=np.max(F_values)
max_DNA=pop[np.argmax(F_values)]
# 选择
pop = select(pop,fitness)
# 交叉、变异,父=子
pop_copy = pop.copy()
for parent in pop:
child = change(parent,pop_copy)
child = variation(child,PM)
parent= child
print("The maximum is:",max)
print("The DNA is:",max_DNA)
print("The X is:",decode(max_DNA))
整体代码
import numpy as np
pop_size = 10 # 种群数量
PC=0.8 # 交叉概率
PM=0.01 #变异概率
X_max=2 #最大值
X_min=-1 #最小值
DNA_SIZE=10 #DNA长度与保留位数有关,2**10 当前保留3位小数点
N_GENERATIONS=1000#迭代次数
#定义函数
def f(x):
return x*np.sin(10*np.pi*x)+1.0
#解码
def decode(pop):
return pop.dot(2 ** np.arange(DNA_SIZE)[::-1]) *(X_max-X_min)/ float(2**DNA_SIZE-1) +X_min
#计算适应度
def fitnessget(pred):
return pred + 1e-3 - np.min(pred)
#选择
def select(pop, fitness):
idx = np.random.choice(np.arange(pop_size), size=pop_size, replace=True,p=fitness/fitness.sum())
return pop[idx]
#交叉
def change(parent, pop):
if np.random.rand() < PC:
i_ = np.random.randint(0, pop_size, size=1)
cross_points = np.random.randint(0, 2, size=DNA_SIZE).astype(bool)
parent[cross_points] = pop[i_, cross_points]
return parent
#变异
def variation(child,pm):
for point in range(DNA_SIZE):
if np.random.rand() < pm:
child[point] = 1 if child[point] == 0 else 0
return child
pop = np.random.randint(2, size=(pop_size, DNA_SIZE))
for i in range(N_GENERATIONS):
#解码
X_value= decode(pop)
#获取目标函数值
F_values = f(X_value)
#获取适应值
fitness = fitnessget(F_values)
if(i==0):
max=np.max(F_values)
max_DNA = pop[np.argmax(F_values)]
if(max<np.max(F_values)):
max=np.max(F_values)
max_DNA=pop[np.argmax(F_values)]
#选择
pop = select(pop,fitness)
pop_copy = pop.copy()
for parent in pop:
child = change(parent,pop_copy)
child = variation(child,PM)
parent= child
print("The maximum is:",max)
print("The DNA is:",max_DNA)
print("The X is:",decode(max_DNA))