智能优化算法——遗传算法(Python&Matlab实现)[2]

目录

1 知识点

2 一元函数的优化问题

2.1 案例

​ 2.2 Python实现

2.3 Matlab实现

3 二元函数的优化问题

3.1 案例

3.2 Python实现

3.3 Matlab实现


1 知识点

我们在前面已经把遗传算法的知识点梳理过了——智能优化算法之遗传算法知识点

下面我们主要分享一元函数的优化问题 二元函数的优化问题:

2 一元函数的优化问题

2.1 案例

一元函数的优化问题:

f(x)=xcos(5\pi x)+3.5

利用遗传算法计算函数在区间[-1,2.5]上的最值。

2.2 Python实现

# -*- 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

2.3 Matlab实现

%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<num_gen fit_v=ranking(-opt_minmax*fun_v); %计算目标函数的适应度 %ranking 函数为查询结果数据集分区中的每一行,并返回一个序列值。依据此函数,一些可能行可能取得和其他行一样的序列值 selchrom=select('rws',chrom,fit_v,gap); %使用轮盘度方式选择 selchrom=recombin('xovsp',selchrom); %交叉 selchrom=mut(selchrom); %变异 x=bs2rv(selchrom,fieldd); %子代个体翻译 fun_v_sel=fun_sigv(x); %计算子代个体对应目标函数值 [chrom,fun_v]=reins(chrom,selchrom,1,1,opt_minmax*fun_v,opt_minmax*fun_v_sel); %根据目标函数值将子代个体插入新种群 [f,id]=max(fun_v); %寻找当前种群最优解 x=bs2rv(chrom,fieldd); %翻译初始化种群为10进制 f=f*opt_minmax; fun_v=fun_v*opt_minmax; k_gen=k_gen+1;%记录遗传次数 trace(k_gen,1)=f; trace(k_gen,2)=mean(fun_v); end plot(x(id),f,'r*') figure plot(trace(:,1),'r-*') hold on plot(trace(:,2),'b-o') legend('各子代种群最优解','各子代种群平均值') xlabel('迭代次数') ylabel('目标函数优化情况') title('一元函数优化过程')
function y=fun_sigv(x) y=x.*cos(5*pi*x)+3.5;

MATLAB:未定义函数或变量 ‘crtbp‘问题解决!

3 二元函数的优化问题

3.1 案例

3.2 Python实现

#==========导入相关库================# 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)

3.3 Matlab实现

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<num_gen fit_v=ranking(-opt_minmax*fun_v); %计算目标函数的适应度 selchrom=select('rws',chrom,fit_v,gap); %使用轮盘度方式选择 selchrom=recombin('xovsp',selchrom); %交叉 selchrom=mut(selchrom); %变异 x=bs2rv(selchrom,fieldd); %子代个体翻译 fun_v_sel=fun_mutv(x(:,1),x(:,2));%x.*sin(10*pi*x)+2; %计算子代个体对应目标函数值 fit_v_sel=ranking(-opt_minmax*fun_v_sel); [chrom,fun_v]=reins(chrom,selchrom,1,1,opt_minmax*fun_v,opt_minmax*fun_v_sel); %根据目标函数值将子代个体插入新种群 [f,id]=max(fun_v); %寻找当前种群最优解 x=bs2rv(chrom(id,:),fieldd); f=f*opt_minmax; fun_v=fun_v*opt_minmax; plot3(x(1,1),x(1,2),f,'k*') hold on k_gen=k_gen+1; trace(k_gen,1)=f; trace(k_gen,2)=mean(fun_v); end figure plot(trace(:,1),'r-*') hold on plot(trace(:,2),'b-o') legend('各子代种群最优解','各子代种群平均值') xlabel('迭代次数') ylabel('目标函数优化情况') title('多元函数优化过程')%其中,fun_mutv(x,y)为多元目标函数,可以根据具体的需要来定义。本题中fun_mutv(x,y)的定义如下:
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;

此刻晚上两点,把问题都解决完了,心里踏实多啦,睡觉……..

本网页由快兔兔AI采集器生成,目的为演示采集效果,若侵权请及时联系删除。

原文链接:https://blog.csdn.net/weixin_46039719/article/details/122872298

更多内容