遗传算法(GA)的实现(基于二进制编码,Python附源码)

遗传算法的实现思路

遗传算法(GA)是一种借鉴生物进化理论,仿照生物的多代遗传过程的随机搜索算法,它以目标问题的不同解作为不同的个体生成种群,然后对种群进行选择、交配、变异操作来寻求最优个体以实现对目标问题的求解。
其主要算法步骤如下:
1)编码生成种群个体,编码方式一般为实数编码或二进制编码;
2)计算种群个体适应度值;
3)选择操作,选出种群中适应度较高的个体,一般使用轮盘赌方法或比例选择法进行选择;
4)交叉操作,根据交叉概率对经过选择后的种群个体进行个体间基因片段的交换,交叉概率一般为固定值;
5)变异操作,根据变异概率对经过选择后的种群个体进行基因片段的改变,变异概率一般为固定值。
6)重复步骤3到步骤5,当达到最大迭代次数或满足停止条件后停止迭代,然后输出种群中的最优个体。

基于二进制编码方式的遗传算法的实现

待求解问题Rastrigin函数:
f(x)=20+x^2-10 cos⁡(2πx)+y^2-10cos⁡(2πy)
求最小值,取值范围:x∈[-5,5],y∈[-5,5],精度精确到小数点后五位。
1、库的导入
NumPy(Numerical Python)是 Python 语言的一个扩展程序库,支持大量的维度数组与矩阵运算,此外也针对数组运算提供大量的数学函数库。
Matplotlib 是 Python 的绘图库,它能让使用者很轻松地将数据图形化,并且提供多样化的输出格式。
这两个库需要提前安装在当前python路径下,在cmd中执行安装指令即可安装在当前python路径,指令如下:

pip install numpy
pip install matplotlib

库的导入指令如下:

import numpy as np
import matplotlib.pyplot as plt

2、目标函数
将上述问题中的x,y视作种群中的一个个体X,待求解问题f(x)即为目标函数,同时作为适应度函数。

def fitness_func(X):
    pi = np.pi
    x = X[:, 0]
    y = X[:, 1]
    return 20 + x ** 2 - 10 * np.cos(2 * pi * x) + y ** 2 - 10 * np.cos(2 * pi * y)

3、编码统一函数
将二进制编码的每个个体转换成十进制编码,由于for函数是从第0位开始,而二进制转换成十进制需要从个位数开始,因此需要另外的计算将其转换成原数值。

def decode(x, a, b):
    xt = 0
    for i in range(len(x)):
        xt = xt + x[i] * np.power(2, i)
    return a + xt * (b - a) / (np.power(2, len(x)) - 1)

4、个体解码函数
调用3中的解码统一函数decode(),将每个个体解码成由x,y组成的数组形式。

def decode_X(X: np.array):
    # X.shape[0]为50,即个体数量
    X2 = np.zeros((X.shape[0], 2))
    for i in range(X.shape[0]):
        #获得x的十进制数
        xi = decode(X[i, :20], -5, 5)
        #获得y的十进制数
        yi = decode(X[i, 20:], -5, 5)
        #将x、y组成的个体赋给数组X2
        X2[i, :] = np.array([xi, yi])
    return X2

5、选择函数
使用比例选择法,由于是求最小值,因此要取倒数来评价适应度值,适应度值越大,选择的概率越大。

def select(X, fitness):
    fitness = 1 / fitness  # fitness越小表示越优秀,被选中的概率越大,因此取倒数做1/fitness 处理
    fitness = fitness / fitness.sum()  # 获得每个个体的概率
    # 将X的每一行(也就是每个个体)选取出来,并排排在一起生成一个新的列表,然后将列表转换成一维数组idx
    idx = np.array(list(range(X.shape[0])))
    # 从idx中按照适应度值随机选出50个个体,生成一维数组X2_idx,每个个体被选中的概率与其适应度大小相关
    X2_idx = np.random.choice(idx, size=X.shape[0], p=fitness)
    # 将X2_idx里的每一列取出来作为数组X的每一行,之后将数组X赋给X2
    X2 = X[X2_idx, :]
    return X2

6、交叉函数
每两个个体为一组,针对每组个体的每个基因,随机生成0-1之间的随机数,与交叉概率比较,若小于交叉概率,则对该基因进行交换,完成交换后,新的一组个体取代原先的一组个体。

def crossover(X, c):
    for i in range(0, X.shape[0], 2):
        xa = X[i, :]
        xb = X[i + 1, :]
        # X.shape[1]为40,即二进制编码长度
        for j in range(X.shape[1]):
            # 产生0-1区间的均匀分布随机数,判断是否需要进行交叉替换
            if np.random.rand() < c:
                # 如果进行交叉,则将对应的第j个位置的数进行交叉
                xa[j], xb[j] = xb[j], xa[j]
        # 用新的个体取代原先的个体        
        X[i, :] = xa
        X[i + 1, :] = xb
    return X

7、变异函数
针对种群中的每个个体的每个基因,随机生成0-1之间的随机数,与变异概率比较,若小于变异概率,则对该基因进行变异,即0变成1,1变成0,完成变异后,新的个体取代原先的个体。

def mutation(X, m):
    for i in range(X.shape[0]):
        for j in range(X.shape[1]):
            if np.random.rand() < m:
                # 0变成1,1变成0
                X[i, j] = (X[i, j] + 1) % 2
    return X

8、算法主流程
将交叉概率设为0.3、变异概率设为0.05,种群数量为50,每个个体都是由x,y组成,且x,y都是二进制编码,由于x与y取值范围在[-5,5]之间,且精确到小数点后五位,因此x、y的编码长度均为20,即每个个体的编码长度为40。
二进制编码随机初始化种群个体后进入循环迭代过程,迭代次数为100次,每次迭代过程中依次进行选择、交叉、变异操作,之后将种群解码并计算适应度值,然后保存此次迭代中的最优适应度值(best_fitness)以及对应的最优个体(best_xy),然后将此时的种群作为下一次迭代时的初始种群。
每次迭代过程中输出当前迭代次数以及最优适应度值。
迭代结束后输出最优适应度值以及对应的个体取值。

c = 0.3  # 交叉概率
m = 0.05  # 变异概率
best_fitness = []  # 记录每次迭代最优适应度值
best_xy = [] # 记录每次迭代最优个体
iter_num = 100  # 最大迭代次数
X0 = np.random.randint(0, 2, (50, 40))  # 随机初始化种群,50个个体,每个个体编码长度为40,为50*40的0-1矩阵
for i in range(iter_num):
    X1 = decode_X(X0)  # 染色体解码
    fitness = fitness_func(X1)  # 计算个体适应度
    X2 = select(X0, fitness)  # 选择操作
    X3 = crossover(X2, c)  # 交叉操作
    X4 = mutation(X3, m)  # 变异操作
    # 将二进制转换成十进制,分别获得x,y
    X5 = decode_X(X4)
    # 计算适应度值
    fitness = fitness_func(X5)
    # 计算结果最小的即为最优适应度值,保存到best_fitness中
    best_fitness.append(fitness.min())
    # 将最优个体保存到best_xy中
    x, y = X5[fitness.argmin()]
    best_xy.append((x, y))
    # 将此次的种群作为新一次迭代过程中的初始种群
    X0 = X4
    # 输出当前迭代最优效果
    print("当前迭代次数:", i+1)
    print("最优适应度值是:", best_fitness[i])
#迭代结束后的最终效果
print("最优值是:%.5f" % best_fitness[-1])
print("最优解是:x=%.5f, y=%.5f" % best_xy[-1])

9、结果绘图
将best_fitness(每次迭代的最优适应度值)进行绘图并保存,可通过图片查看迭代过程中最优适应度值的变化情况。

plt.plot(best_fitness, color='r')
plt.savefig("GA.png")
plt.show()

图中横轴为迭代次数,纵轴为最优适应度值。
遗传算法(GA)的实现(基于二进制编码,Python附源码)_第1张图片

你可能感兴趣的:(群智能优化算法,python,算法,numpy)