进化算法------代码示例

前言

遗传算法就是在一个解空间上,随机的给定一组解,这组解称为父亲种群,通过这组解的交叉,变异,构建出新的解,称为下一代种群,然后在目前已有的所有解中抽取表现好的解组成新的父亲种群,然后继续上面的过程,直到达到了迭代条件或者获取到了最优解。

进化算法流程框架

下面我们来解释下这个流程图里面的一些概念

  • 适应度

所谓的适应度,本质上可以理解为一个代价函数,或者一个规则,通过对初始种群中的个体计算适应度,能够得到对初始种群中的个体是否优劣的一个度量

  • 选择

选择操作是根据种群中的个体的适应度函数值所度量的优、劣程度决定它在下一代是被淘汰还是被遗传

  • 交叉
    交叉操作是将选择的两个个体p1和 p2
    作为父母节点,将两者的部分码值进行交换。假设有下面的两个节点的二进制编码表示:

    随机产生一个1到7之间的随机数,假设为3,则将p1和 p2的低三位进行互换,如下图所示,就完成了交叉操作:
  • 变异
    变异操作就是改变一个DNA序列上某一个点,

    我们以一定的概率进行变异的操作,例如上方的DNA序列的第6个结点,由1变成了0

代码示例

1、寻找函数最大值

首先我们生成POP_SIZE个长度为DNA_SIZE的DNA序列

csharp 复制代码
pop = np.random.randint(2, size=(POP_SIZE, DNA_SIZE))

定义函数图像

csharp 复制代码
def F(x):
    """
    定义一个函数,就是图像中的线条
    :param x:
    :return:
    """
    return np.sin(10*x)*x + np.cos(2*x)*x     # to find the maximum of this function

我们可以将DNA转换为函数中x轴中的某个点,将0 1 DNA序列翻译成范围在(0, 5)的数字

csharp 复制代码
def translateDNA(pop):
    """
    将0 1 DNA序列翻译成范围在(0, 5)的数字
    :param pop:
    :return:
    """
    return pop.dot(2 ** np.arange(DNA_SIZE)[::-1]) / float(2**DNA_SIZE-1) * X_BOUND[1]

x轴上对应的y轴上的值,我们将其称为适应度

csharp 复制代码
def get_fitness(pred):
    """
    获取个体的适用度
    :param pred:
    :return:
    """
    return pred + 1e-3 - np.min(pred)   #防止适应度为负数

我们从种群中选择个体
注意: 并不是每次都选择适应度最高的个体,只是适应度高的个体选择的概率比较大,其它适应度较低的个体,选择的概率小,将来适应度低的个体变异后,适应度可能会变大

csharp 复制代码
def select(pop, fitness):    # nature selection wrt pop's fitness
    """
    从种群中选择
    :param pop:
    :param fitness:
    :return: 所选个体的下标,可重复选择replace=True
    """
    idx = np.random.choice(np.arange(POP_SIZE), size=POP_SIZE, replace=True,
                           p=fitness/fitness.sum())
    return pop[idx]

 pop = select(pop, fitness)

之后我们对选择后的种群进行交叉和变异

csharp 复制代码
def crossover(parent, pop):     # mating process (genes crossover)
    """
    交叉配对
    :param parent:
    :param pop:
    :return:
    """
    if np.random.rand() < CROSS_RATE:
        i_ = np.random.randint(0, POP_SIZE, size=1)                             # select another individual from pop 从种群中选择一个个体,
        cross_points = np.random.randint(0, 2, size=DNA_SIZE).astype(np.bool_)   # choose crossover points  生成要交叉的位置
        parent[cross_points] = pop[i_, cross_points]                            # mating and produce one child   进行交叉
    return parent

def mutate(child):
    """
    变异
    :param child:
    :return:
    """
    for point in range(DNA_SIZE):
        if np.random.rand() < MUTATION_RATE:
            child[point] = 1 if child[point] == 0 else 0
    return child

 # 复制一个副本
 pop_copy = pop.copy()
 # 进行遗传 和变异
 for parent in pop:
     child = crossover(parent, pop_copy)
     child = mutate(child)
     parent[:] = child  # parent is replaced by its child 父亲个体被孩子代替

最后,我们对其迭代多次

csharp 复制代码
    for _ in range(N_GENERATIONS):
        # 得到图像上的y值
        F_values = F(translateDNA(pop))
        # 更新散点图
        if 'sca' in globals(): sca.remove()
        sca = plt.scatter(translateDNA(pop), F_values, s=200, lw=0, c='red', alpha=0.5)
        plt.pause(0.1)
        # 获取每一个个体的适应度
        fitness = get_fitness(F_values)

        #获取最好适用度的个体下标
        i = np.argmax(fitness)
        print("最优DNA",pop[i,:])
        pop = select(pop, fitness)
        # 复制一个副本
        pop_copy = pop.copy()
        # 进行遗传 和变异
        for parent in pop:
            child = crossover(parent, pop_copy)
            child = mutate(child)
            parent[:] = child  # parent is replaced by its child 父亲个体被孩子代替

完整代码:

csharp 复制代码
#!/usr/bin/env python 
# -*- coding:utf-8 -*-
import time

import numpy as np
import matplotlib.pyplot as plt

DNA_SIZE = 10            # DNA length  DNA长度
POP_SIZE = 100           # population size  种群大小
CROSS_RATE = 0.8         # mating probability (DNA crossover)  交叉配对的概率
MUTATION_RATE = 0.003    # mutation probability  编译的概率
N_GENERATIONS = 200     #   代数
X_BOUND = [0, 5]         # x upper and lower bounds   x轴范围

def F(x):
    """
    定义一个函数,就是图像中的线条
    :param x:
    :return:
    """
    return np.sin(10*x)*x + np.cos(2*x)*x     # to find the maximum of this function

def get_fitness(pred):
    """
    获取个体的适用度
    :param pred:
    :return:
    """
    return pred + 1e-3 - np.min(pred)   #防止适应度为负数
def translateDNA(pop):
    """
    将0 1 DNA序列翻译成范围在(0, 5)的数字
    :param pop:
    :return:
    """
    return pop.dot(2 ** np.arange(DNA_SIZE)[::-1]) / float(2**DNA_SIZE-1) * X_BOUND[1]


def select(pop, fitness):    # nature selection wrt pop's fitness
    """
    从种群中选择
    :param pop:
    :param fitness:
    :return: 所选个体的下标,可重复选择replace=True
    """
    idx = np.random.choice(np.arange(POP_SIZE), size=POP_SIZE, replace=True,
                           p=fitness/fitness.sum())
    return pop[idx]



def crossover(parent, pop):     # mating process (genes crossover)
    """
    交叉配对
    :param parent:
    :param pop:
    :return:
    """
    if np.random.rand() < CROSS_RATE:
        i_ = np.random.randint(0, POP_SIZE, size=1)                             # select another individual from pop 从种群中选择一个个体,
        cross_points = np.random.randint(0, 2, size=DNA_SIZE).astype(np.bool_)   # choose crossover points  生成要交叉的位置
        parent[cross_points] = pop[i_, cross_points]                            # mating and produce one child   进行交叉
    return parent

def mutate(child):
    """
    变异
    :param child:
    :return:
    """
    for point in range(DNA_SIZE):
        if np.random.rand() < MUTATION_RATE:
            child[point] = 1 if child[point] == 0 else 0
    return child



if __name__ == '__main__':
    # initialize the pop DNA   s生成0-1的POP_SIZE行 DNA_SIZE列的种群
    pop = np.random.randint(2, size=(POP_SIZE, DNA_SIZE))
    plt.ion()  # something about plotting
    # x轴
    x = np.linspace(*X_BOUND, 200)
    plt.plot(x, F(x))
    # 迭代N_GENERATIONS次
    for _ in range(N_GENERATIONS):
        # 得到图像上的y值
        F_values = F(translateDNA(pop))
        # 更新散点图
        if 'sca' in globals(): sca.remove()
        sca = plt.scatter(translateDNA(pop), F_values, s=200, lw=0, c='red', alpha=0.5)
        plt.pause(0.1)
        # 获取每一个个体的适应度
        fitness = get_fitness(F_values)

        #获取最好适用度的个体下标
        i = np.argmax(fitness)
        print("最优DNA",pop[i,:])
        pop = select(pop, fitness)
        # 复制一个副本
        pop_copy = pop.copy()
        # 进行遗传 和变异
        for parent in pop:
            child = crossover(parent, pop_copy)
            child = mutate(child)
            parent[:] = child  # parent is replaced by its child 父亲个体被孩子代替

    plt.ioff()
    plt.show()
相关推荐
啊阿狸不会拉杆32 分钟前
《算法导论》第 32 章 - 字符串匹配
开发语言·c++·算法
小学生的信奥之路1 小时前
洛谷P3817题解:贪心算法解决糖果分配问题
c++·算法·贪心算法
你知道网上冲浪吗2 小时前
【原创理论】Stochastic Coupled Dyadic System (SCDS):一个用于两性关系动力学建模的随机耦合系统框架
python·算法·数学建模·数值分析
地平线开发者3 小时前
征程 6 | PTQ 精度调优辅助代码,总有你用得上的
算法·自动驾驶
Tisfy4 小时前
LeetCode 837.新 21 点:动态规划+滑动窗口
数学·算法·leetcode·动态规划·dp·滑动窗口·概率
CoovallyAIHub4 小时前
为高空安全上双保险!无人机AI护航,YOLOv5秒判安全带,守护施工生命线
深度学习·算法·计算机视觉
huangzixuan10074 小时前
08.18总结
算法·深度优先·图论
逆向菜鸟4 小时前
【摧毁比特币】椭圆曲线象限细分求k-陈墨仙
python·算法
DolphinDB5 小时前
DolphinDB 回测插件快速上手
算法
利刃大大5 小时前
【动态规划:路径问题】最小路径和 && 地下城游戏
算法·动态规划·cpp·路径问题