目录
1 知识点
2 一元函数的优化问题
2.1 案例
2.2 Python实现
2.3 Matlab实现
3 二元函数的优化问题
3.1 案例
3.2 Python实现
3.3 Matlab实现
我们在前面已经把遗传算法的知识点梳理过了——智能优化算法之遗传算法知识点。
下面我们主要分享一元函数的优化问题 和二元函数的优化问题:
一元函数的优化问题:
利用遗传算法计算函数在区间[-1,2.5]上的最值。
# -*- coding: utf-8 -*-
# ========导入相关包============
import numpy as np
import matplotlib.pyplot as plt
# =====适应度函数,求取最大、小值======
def fitness(x):
return x*np.cos(5*np.pi*x)+3.5 #最大
#return -(x * np.cos(5 * np.pi * x) + 3.5)# 最小
# =====个体类============
class indivdual:
def __init__(self):
self.x = 0 # 染色体编码
self.fitness = 0 # 个体适应度值
def __eq__(self, other):
self.x = other.x
self.fitness = other.fitness
# =====初始化种群===========
# pop为种群适应度存储数组,N为个体数
def initPopulation(pop, N):
for i in range(N):
ind = indivdual() # 个体初始化
ind.x = np.random.uniform(-1, 2.5) # 个体编码。-10,10的正态分布,可以自己设定限定边界
ind.fitness = fitness(ind.x) # 计算个体适应度函数值
pop.append(ind) # 将个体适应度函数值添加进种群适应度数组pop
# ======选择过程==============
def selection(N):
# 种群中随机选择2个个体进行变异(这里没有用轮盘赌,直接用的随机选择)
return np.random.choice(N, 2)
# ===结合/交叉过程=============
def crossover(parent1, parent2):
child1, child2 = indivdual(), indivdual() # 父亲,母亲初始化
child1.x = 0.9 * parent1.x + 0.1 * parent2.x # 交叉0.9,0.1,可以设置其他系数
child2.x = 0.1 * parent1.x + 0.9 * parent2.x
child1.fitness = fitness(child1.x) # 子1适应度函数值
child2.fitness = fitness(child2.x) # 子2适应度函数值
return child1, child2
# =====变异过程==========
def mutation(pop):
# 种群中随机选择一个进行变异
ind = np.random.choice(pop)
# 用随机赋值的方式进行变异
ind.x = np.random.uniform(-1, 2.5)
ind.fitness = fitness(ind.x)
# ======最终执行===========
def implement():
# ===种群中个体数量====
N = 40
# 种群
POP = []
# 迭代次数
iter_N = 400
# 初始化种群
initPopulation(POP, N)
# ====进化过程======
for it in range(iter_N): # 遍历每一代
a, b = selection(N) # 随机选择两个个体
if np.random.random() < 0.65: # 以0.65的概率进行交叉结合
child1, child2 = crossover(POP[a], POP[b])
new = sorted([POP[a], POP[b], child1, child2], key=lambda ind: ind.fitness,
reverse=True) # 将父母亲和子代进行比较,保留最好的两个
POP[a], POP[b] = new[0], new[1]
if np.random.random() < 0.1: # 以0.1的概率进行变异
mutation(POP)
POP.sort(key=lambda ind: ind.fitness, reverse=True)
return POP
if __name__ == '__main__':
POP = implement()
# =======绘图代码============
def func(x):
return x*np.cos(5*np.pi*x)+3.5
#return -(x * np.cos(5 * np.pi * x) + 3.5)
x = np.linspace(-1, 2.5, 100)
y = func(x)
scatter_x = np.array([ind.x for ind in POP])
scatter_y = np.array([ind.fitness for ind in POP])
best = sorted(POP, key=lambda POP: POP.fitness, reverse=True)[0] # 最佳点
print('best_x:', best.x)
print('best_y:', best.fitness)
plt.plot(x, y)
# plt.scatter(scatter_x, scatter_y, c='r')
plt.scatter(best.x, best.fitness, c='g', label='best point')
plt.legend()
plt.show()
#==========结果============
#===(1)最大值====
best_x: 2.40537584441956
best_y: 5.896804913355371
#===(1)最小值====
best_x: 2.196313082366646
best_y: -1.3073691355607653
%opt_minmax=-1; %目标优化类型:1最大化、-1最小化
opt_minmax=1;
num_ppu=50; %种群规模:个体个数
num_gen=60; %最大遗传代数
len_ch=20; %基因长度
gap=0.9; %代沟
sub=-1; %变量取值下限
up=2.5; %变量取值上限
cd_gray=1; %是否选择格雷编码方式:1是0否
sc_log=0; %是否选择对数标度:1是0否
trace=zeros(num_gen,2); %遗传迭代性能跟踪器,生成60行2列0矩阵
fieldd=[len_ch;sub;up;1-cd_gray;sc_log;1;1]; %区域描述器
chrom=crtbp(num_ppu,len_ch); %初始化生成种群,生成一个50*20的矩阵,矩阵元素是0-1随机数
k_gen=0;%初始化遗传次数
x=bs2rv(chrom,fieldd); %翻译初始化种群为10进制
fun_v=fun_sigv(x); %计算目标函数值
tx=sub:.01:up;
plot(tx,fun_sigv(tx))
xlabel('x')
ylabel('y')
title('一元函数优化结果')
hold on
while k_gen
function y=fun_sigv(x)
y=x.*cos(5*pi*x)+3.5;
MATLAB:未定义函数或变量 ‘crtbp‘问题解决!
#==========导入相关库================#
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm #绘制3d曲面时用于给图上色:【ax.plot_surface(X, Y, Z, rstride = 1, cstride = 1, cmap = cm.coolwarm)】
from mpl_toolkits.mplot3d import Axes3D #用于画三维图,将二维图变换为三维图: 【fig = plt.figure()】 【ax = Axes3D(fig)】
#=======初始化及变量范围==============#
DNA_SIZE = 24
POP_SIZE = 200
CROSSOVER_RATE = 0.8
MUTATION_RATE = 0.005
N_GENERATIONS = 50
X_BOUND = [-10, 10]
Y_BOUND = [-10, 10]
#=====目标函数===========#
def F(x, y):
t1,t2=0,0
for i in range(5):
t1 = t1 + i * np.cos((i + 1) * x + i)
t2 = t2 + i * np.cos((i + 1) * y + i)
return t1*t2
#return x + 16 * np.sin(5 * x) + 10 * np.cos(4 * x)
#======3D绘图==========#
def plot_3d(ax):
X = np.linspace(*X_BOUND, 10)
Y = np.linspace(*Y_BOUND, 10)
X, Y = np.meshgrid(X, Y)
Z = F(X, Y)
ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=cm.coolwarm)
ax.set_zlim(-60,60)
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')
plt.pause(3)
plt.show()
#=======最大适应度==========#
def get_fitness(pop):
x, y = translateDNA(pop)
pred = F(x, y)
return (pred - np.min(
pred)) + 1e-3 # 减去最小的适应度是为了防止适应度出现负数,通过这一步fitness的范围为[0, np.max(pred)-np.min(pred)],最后在加上一个很小的数防止出现为0的适应度
'''
(1)最小值适应度函数
def get_fitness(pop):
x,y = translateDNA(pop)
pred = F(x, y)
return -(pred - np.max(pred)) + 1e-3
(2)np.min用法
import numpy as np
a = np.array([[1,5,3],[4,2,6]])
print(a.min()) #无参,所有中的最小值 print(min(a))
print(a.min(0)) # axis=0; 每列的最小值 print(min(a, axis = 0))
print(a.min(1)) # axis=1;每行的最小值 print(min(a, axis = 1))
'''
#======基因编译========#
def translateDNA(pop): # pop表示种群矩阵,一行表示一个二进制编码表示的DNA,矩阵的行数为种群数目
x_pop = pop[:, 1::2] # 奇数列表示X
y_pop = pop[:, ::2] # 偶数列表示y
# pop:(POP_SIZE,DNA_SIZE)*(DNA_SIZE,1) --> (POP_SIZE,1)
x = x_pop.dot(2 ** np.arange(DNA_SIZE)[::-1]) / float(2 ** DNA_SIZE - 1) * (X_BOUND[1] - X_BOUND[0]) + X_BOUND[0]
y = y_pop.dot(2 ** np.arange(DNA_SIZE)[::-1]) / float(2 ** DNA_SIZE - 1) * (Y_BOUND[1] - Y_BOUND[0]) + Y_BOUND[0]
return x, y
#=======染色体交叉=====#
def crossover_and_mutation(pop, CROSSOVER_RATE=0.8):
new_pop = []
for father in pop: # 遍历种群中的每一个个体,将该个体作为父亲
child = father # 孩子先得到父亲的全部基因(这里我把一串二进制串的那些0,1称为基因)
if np.random.rand() < CROSSOVER_RATE: # 产生子代时不是必然发生交叉,而是以一定的概率发生交叉
mother = pop[np.random.randint(POP_SIZE)] # 再种群中选择另一个个体,并将该个体作为母亲
cross_points = np.random.randint(low=0, high=DNA_SIZE * 2) # 随机产生交叉的点
child[cross_points:] = mother[cross_points:] # 孩子得到位于交叉点后的母亲的基因
mutation(child) # 每个后代有一定的机率发生变异
new_pop.append(child)
return new_pop
'''【1】 np.random.rand()
注:使用方法与np.random.randn()函数相同
作用: 通过本函数可以返回一个或一组服从“0~1”均匀分布的随机样本值。随机样本取值范围是[0,1),不包括1。
【2】np.random.randn(d0,d1,d2……dn)
1)当函数括号内没有参数时,则返回一个浮点数;
2)当函数括号内有一个参数时,则返回秩为1的数组,不能表示向量和矩阵;
3)当函数括号内有两个及以上参数时,则返回对应维度的数组,能表示向量或矩阵;
4)np.random.standard_normal()函数与np.random.randn()类似,但是np.random.standard_normal()
的输入参数为元组(tuple).
5)np.random.randn()的输入通常为整数,但是如果为浮点数,则会自动直接截断转换为整数。
作用:通过本函数可以返回一个或一组服从标准正态分布的随机样本值。
【3】np.random.randint()
numpy.random.randint(low, high=None, size=None, dtype=’l’)
输入:
low—–为最小值
high—-为最大值
size—–为数组维度大小
dtype—为数据类型,默认的数据类型是np.int。
返回值:
返回随机整数或整型数组,范围区间为[low,high),包含low,不包含high;
high没有填写时,默认生成随机数的范围是[0,low)'''
#==============变异==========================#
def mutation(child, MUTATION_RATE=0.003):
if np.random.rand() < MUTATION_RATE: # 以MUTATION_RATE的概率进行变异
mutate_point = np.random.randint(0, DNA_SIZE * 2) # 随机产生一个实数,代表要变异基因的位置
child[mutate_point] = child[mutate_point] ^ 1 # 将变异点的二进制为反转
#=============选择==========================#
def select(pop, fitness): # nature selection wrt pop's fitness
idx = np.random.choice(np.arange(POP_SIZE), size=POP_SIZE, replace=True,
p=(fitness) / (fitness.sum()))
return pop[idx]
'''
np.random.choice()用法
1、参数意思分别 是从a 中以概率P,随机选择3个, p没有指定的时候相当于是一致的分布,a为一维数组或int,如果是int,则生成随机样本,就好像a是np.arange(N)一样。
a1 = np.random.choice(a=5, size=3, replace=False, p=None)
2、非一致的分布,会以多少的概率提出来
a2 = np.random.choice(a=5, size=3, replace=False, p=[0.2, 0.1, 0.3, 0.4, 0.0])
replacement 代表的意思是抽样之后还放不放回去,如果是False的话,那么出来的三个数都不一样,如果是True的话, 有可能会出现重复的,因为前面的抽的放回去了。
'''
#======打印最大适应度,最优基因,X,Y==============#
def print_info(pop):
fitness = get_fitness(pop)
max_fitness_index = np.argmax(fitness)
print("max_fitness:", fitness[max_fitness_index])
x, y = translateDNA(pop)
print("最优的基因型:", pop[max_fitness_index])
print("(x, y):", (x[max_fitness_index], y[max_fitness_index]))
#==================主函数====================#
def main():
fig = plt.figure()
ax = Axes3D(fig)
plt.ion() # 将画图模式改为交互模式,程序遇到plt.show不会暂停,而是继续执行
plot_3d(ax)
pop = np.random.randint(2, size=(POP_SIZE, DNA_SIZE * 2)) # matrix (POP_SIZE, DNA_SIZE)
for _ in range(N_GENERATIONS): # 迭代N代
x, y = translateDNA(pop)
if 'sca' in locals():
sca.remove()
sca = ax.scatter(x, y, F(x, y), c='black', marker='o');
plt.show();
plt.pause(0.1)
pop = np.array(crossover_and_mutation(pop, CROSSOVER_RATE))
# F_values = F(translateDNA(pop)[0], translateDNA(pop)[1])#x, y --> Z matrix
fitness = get_fitness(pop)
pop = select(pop, fitness) # 选择生成新的种群
print_info(pop)
plt.ioff()
plot_3d(ax)
#结果
max_fitness: 0.8502111412747931
最优的基因型: [1 0 1 1 0 1 0 1 0 0 1 1 1 1 0 0 1 0 0 0 1 1 0 0 0 1 0 0 1 0 1 1 0 1 0 0 1
0 1 0 1 1 0 1 1 0 0 1]
(x, y): (-0.7685691576343263, 5.518563718710167)
clc
clear all
opt_minmax=-1; %目标优化类型:1最大化、-1最小化
%opt_minmax=1;
num_ppu=60; %种群规模:个体个数
num_gen=100; %最大遗传代数
num_v=2; %变量个数
len_ch=20; %基因长度
gap=0.9; %代沟
sub=-10; %变量取值下限
up=10; %变量取值上限
cd_gray=1; %是否选择格雷编码方式:1是0否
sc_log=0; %是否选择对数标度:1是0否
trace=zeros(num_gen,2); %遗传迭代性能跟踪器
fieldd=[repmat([len_ch],[1,num_v]);repmat([sub;up],[1,num_v]);repmat([1-cd_gray;sc_log;1;1],[1,num_v])]; %区域描述器
chrom=crtbp(num_ppu,len_ch*num_v); %初始化生成种群
k_gen=0;
x=bs2rv(chrom,fieldd); %翻译初始化种群为10进制
fun_v=fun_mutv(x(:,1),x(:,2)); %计算目标函数值
[tx,ty]=meshgrid(-10:.1:10);
mesh(tx,ty,fun_mutv(tx,ty))%画三维图
xlabel('x')
ylabel('y')
zlabel('z')
title('多元函数优化结果')
hold on
while k_gen
function my=fun_mutv(x,y)
t1=zeros(size(x));
t2=t1;
for i=1:5
t1=t1+i*cos((i+1)*x+i);
t2=t2+i*cos((i+1)*y+i);
end
my=t1.*t2;
此刻晚上两点,把问题都解决完了,心里踏实多啦,睡觉........