遗传算法的概念和python实现

2023-10-29

    遗传算法是一个非常经典的智能算法,主要用于解决优化问题。本文主要简单介绍一些原理,同时给出一个基于python实现的,用于解决实数内优化问题的模板。

本文参考:

原理:遗传算法入门详解 - 知乎

简单介绍

    遗传算法就是借鉴生物学中的遗传,首先生成若干种群,内有一些个体,也就是解,对不同解设定适应度,采用算子产生新解,不断在种群内遗传优秀基因,最终达到优化的目的。

    所以最终一定有若干个群体,内部的个体都是比较优秀的,不优秀的就被淘汰了。

相关概念

    下面主要是一些基本的概念,参考了上面提到的链接部分,只是摘取了部分并作了一些注解,详细的可以自行去了解。

① 染色体(Chromosome):染色体又可称为基因型个体(individuals),一定数量的个体组成了群体(population),群体中个体的数量叫做群体大小(population size)。

② 位串(Bit String):个体的表示形式。对应于遗传学中的染色体。

③ 基因(Gene):基因是染色体中的元素,用于表示个体的特征。例如有一个串(即染色体)S=1011,则其中的1,0,1,1这4个元素分别称为基因。

④ 特征值( Feature):在用串表示整数时,基因的特征值与二进制数的权一致;例如在串 S=1011 中,基因位置3中的1,它的基因特征值为2;基因位置1中的1,它的基因特征值为8。

⑤ 适应度(Fitness):各个个体对环境的适应程度叫做适应度(fitness)。为了体现染色体的适应能力,引入了对问题中的每一个染色体都能进行度量的函数,叫适应度函数。这个函数通常会被用来计算个体在群体中被使用的概率。

⑥ 基因型(Genotype):或称遗传型,是指基因组定义遗传特征和表现。对于于GA中的位串。

⑦ 表现型(Phenotype):生物体的基因型在特定环境下的表现特征。对应于GA中的位串解码后的参数。

染色体就是一个个体,在具体的计算中就是n维空间内的一个解

位串也就是一个个体的编码后的样子

基因也就是染色体上面所包含的特征,也就是编码后的一位

特征值表示这个位在这个编码规则下的含义

适应度表示在计算过程中被使用的概率,一般是解的优质情况

基因型表示编码后的字符串

表现型表示解码后的参数

遗传步骤

  1. 编码和解码的规则

    两个过程是逆过程,编码就是把一个解编成一个序列,一般采用二进制编码,解码就是反过来。

  2. 生成初始值

    这个过程就是生成需要的变量

    设置最大进化代数 T ,群体大小 M ,交叉概率 Pc ,变异概率 Pm ,随机生成 M 个个体作为初始化群体 P0

  3. 改变适应度

    主要用于改变每个个体的适应度,防止适应度相当,然后就没什么优胜劣汰了。

    一般来讲,是指算法迭代的不同阶段,能够通过适当改变个体的适应度大小,进而避免群体间适应度相当而造成的竞争减弱,导致种群收敛于局部最优解。

    有很多方式,线性非线性...

  4. 遗传算子

    1. 选择

      选择就是在一个旧种群内(包含多个个体)内选择优良的种群,并在其中选择优良的个体进行繁殖,可以达到优生优育。

      常用轮盘赌,也就是个体选择概率为个体的的适应度除以群体的总适应度,适应度高,被选择概率大,可以得到优秀后代。

    2. 交叉

      交叉就是两个染色体之间产生一些交换,从而完成产生新解的操作,常用单点交叉,还有其他...

    3. 变异

      变异就是自身有一定概率发生改变,比如变了一位二进制,也产生了新解。

                这个过程有三种,主要就是用于生成新的解,把不同的解放到一起或者自己生成新解,            同时这几个过程也有多种方式呈现,并不一定拘泥于提到的,针对不同问题也会有不同的解            决方案。

注意点

遗传算法y一般有4个运行参数需要预先设定,即

M :种群大小

T :遗传算法的终止进化代数

Pc :交叉概率,一般为0.4~0.99

Pm :变异概率,一般取0.001~0.1

代码实现

     下面是具体的代码实现,我采用的编码方式就是直接生成浮点数,选择操作每次保留设定比例的个体,交叉操作每次选择两组参数以一定概率进行参数调换,产生新个体,变异操作对每个值以一定概率对某个参数进行重新取值,模拟变异操作。

        记录的参数有三组,分别是每一轮的最优适应度,最优结果和对应的最优参数,最终画图。  

代码

import warnings
from math import log2
import matplotlib.pyplot as plt
import pandas as pd
warnings.filterwarnings('ignore')
import heapq
import itertools
from random import randint, random, uniform
import numpy as np

def select_op(fitness,op,select_rate,best_keep_rate):
    ans_list = []
    # 先选择保留部分
    keep_num = int(best_keep_rate * len(op)*select_rate)
    index_list = list(map(list(fitness).index, heapq.nlargest(keep_num, fitness)))
    for index in index_list:
        ans_list.append(op[index])
    # 保留的
    p =fitness/sum(fitness) # 计算每个个体占比
    p = np.array(list(itertools.accumulate(p))) # 计算累积密度函数
    # 采用轮盘赌方式选择
    for i in range(int(len(op)*select_rate)-keep_num): # 再产生这么多个
        r = random()
        index = np.argmax(p>r) # 找到第一个大于随机的值
        if index == 0 and p[0] < r: # 可能第一个并不大于这个数,可能是没找到,也是返回0
            continue
        ans_list.append(op[index])
    return ans_list

def cross_op(op,cross_rate,num):
    ans_list = []
    num_op = len(op) # 当前数量
    while num > 0:
        max_ = 5 # 最多找5次,如还是相同就用相同的,就说明这个基因很多
        while max_>0:
            n1 = randint(0,num_op-1)
            n2 = randint(0,num_op-1) # 不允许相同个体杂交
            max_ -= 1
            if op[n1] != op[n2]:
                break
        father = op[n1]
        mother = op[n2]
        if random() < cross_rate:
            location = randint(0,len(father)-1) # 随机产生交叉位置
            tmp = father[0:location+1] + mother[location+1:len(father)]
            ans_list.append(tmp)
            num -= 1
    return ans_list

def variation_op_10(new_op,variation_rate,low,high):
    for index,it in enumerate(new_op): # 一定概率变异
        if random() < variation_rate:
            location = randint(0, len(it) - 1)
            it = uniform(low[location],high[location])  # 随机产生数字
            new_op[index][location] = it
    return new_op


# 生成随机初始值
def ini_op(low_paras, high_paras, max_op_size):
    # 计算出每个参数应该占的位数
    st = 0
    ed = -1  # 为了保证st为-1
    para_range = []
    for i in range(len(low_paras)):
        low_it = low_paras[i]
        high_it = high_paras[i]
        num = int(log2(high_it - low_it + 1)) + 1  # 计算二进制位数
        st = ed + 1
        ed += num
        para_range.append((st, ed))  # 加入每个参数的范围,包括起始点和终点(在序列中的)
    op = []
    for i in range(max_op_size):
        tmp = [uniform(low_paras[k], high_paras[k]) for k in range(len(low_paras))]
        op.append(tmp)
    return op, para_range


def cal_fitness(op):
    ans_list = np.zeros((len(op), 1))
    for index, it in enumerate(op):  # 取出每个参数对应的数字
        if un_suit(it):  # 如果不满足约束条件
            ans_list[index] = 1000000000  # 给一个很大的值,最后要统一处理
            continue
        y = func(it)
        ans_list[index] = y
    ans_list = func_fitness(ans_list)
    return ans_list


# 自定义适应度函数计算
def func_fitness(ans_list):
    if model_dir == 'min':
        for index, it in enumerate(ans_list):
            ans_list[index] = 1 / it
    return ans_list


def un_suit(x):  # 定义参数不满足的约束条件
    # 参数范围约束
    for i in range(len(low_paras)):
        if x[i] < low_paras[i] or x[i] > high_paras[i]:
            return True
    # ...自行添加
    return False


# 定义计算函数
def func(x):
    return x[0] ** 2 + x[1] ** (3 / 2) + x[2] + x[3] ** (1 / 2)


# ---配置参数
paras_name = ['x1', 'x2', 'x3', 'x4']
high_paras = [60,60,40,30]  # 参数范围上限
low_paras = [10, 21,3,10]  # 参数范围下限
model_dir = 'min' # max表示越大越好,min表示越小越好
# ---配置遗传算法参数
max_op_size = 200  # 种群大小,这里也是考虑一个种群的优化问题
max_epochs = 200  # 迭代次数,也就是进化次数
cross_rate = 0.8  # 杂交率,选出两个个体之后以这个概率杂交(各取部分基因产生后代)
select_rate = 0.4  # 选择率,也就是选择保留占总的个数(这里实际是利用随机数抽取,而不是按照排序)
variation_rate = 0.1  # 变异率,产生新的个体以这个概率变异(一位重新赋值)
best_keep_rate = 0.1  # 每次选择必定保留的比例(排序靠前的部分)
# ---遗传算法求解
if __name__ == '__main__':
    data = np.array(pd.read_excel('../static/test.xlsx'))  # 读入数据
    op, para_range = ini_op(low_paras, high_paras, max_op_size)  # 初始化种群,返回种群和每个参数的位置范围[(l1,r1),(l2,r2)...]
    best_ans_history = []  # 记录最优答案历史
    best_para_history = []  # 记录最优对应参数
    best_fitness_history = []  # 记录最优适应度
    for i in range(1, max_epochs + 1):
        if i % 50 == 0:
            print('epoch:', i)
        # 计算适应度
        fitness = cal_fitness(op)  # 计算适应度
        index = np.argmax(np.array(fitness)) # 为什么已经保留了最佳适应度,最后的图还是会上下跳动
        best_fitness_history.append(fitness[index])
        best_para_history.append(op[index])
        best_ans_history.append(func(op[index]))
        op = select_op(fitness, op, select_rate, best_keep_rate)  # 选择个体,选择比例为
        # 交叉,产生后代
        new_op = cross_op(op, cross_rate, max_op_size - len(op))  # 后一个参数为需要产生的个数
        # 变异
        new_op = variation_op_10(new_op, variation_rate,low_paras,high_paras)  # 变异
        op.extend(new_op)  # 把新的个体加入群落

    plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
    plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号
    index = np.argmax(best_ans_history)
    print('最优结果为:', best_ans_history[index])
    print('最优参数如下')
    for name,index in zip(paras_name,best_para_history[index]):
        print('{}={}'.format(name,index))
    plt.plot(best_fitness_history, label='适应度曲线变化')
    plt.legend()
    plt.show()

example

就以一个单调函数为例:

x1 ** 2 + x2 ** (3 / 2) + x3 + x4 ** (1 / 2)

设定范围如下:

high_paras = [60,60,40,30]  # 参数范围上限
low_paras = [10, 21,3,10]  # 参数范围下限

迭代两百轮停止,输出结果

最优结果为: 262.08470155055244
最优参数如下
x1=10.92155546612619
x2=22.81339324058242
x3=30.588146368196167
x4=10.573758934746433

输出最优适应度变化曲线:
 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

遗传算法的概念和python实现 的相关文章

随机推荐

  • shell脚本中 if 、for 命令使用方法

    1 if 语句的使用 if语句的语法 if f file then如果有else 为 if then elif then else fi eg 判断某一个文件是否存在 file test 1 hello txt if f test 1 he
  • gigapixel ai 5.1汉化版 附使用教程

    gigapixel ai是一款运用了AI人工智能技术的图片 无损 放大软件 采用了AI深度学习技术 通过它 你可以放大图像并填补其他调整大小的产品遗漏的细节 让低分辨率图片专为高分辨率 高质量图片 而且该软件在功能上与PhotoZoom软件
  • 小程序实现canvas绘制图片和文字并保存到手机

    HTML
  • 如何在OpenCV Python中从立体图像创建深度图?

    翻译 Shahid Akhtar Khan的 How to create a depth map from stereo images in OpenCV Python 可以使用立体 stereo 图像创建深度图 为了从立体图像构建深度图
  • 在弄清什么是真正的OKR之前,别轻易使用

    转自 https www sohu com a 167148654 114819 KR到底是什么 在使用OKR的时候也有哪些注意点 在没弄清楚这些事情 可不要轻易使用 OKR大概在2013年传入中国 开始主要是一些有硅谷背景的初创企业在推行
  • RuntimeError: DataLoader worker (pid(s) 17016, 18312) exited unexpectedly

    RuntimeError DataLoader worker pid s 17016 18312 exited unexpectedly 这个错误通常是由于DataLoader中的一个或多个worker进程crash引起的 原因可能是许多不
  • Android源码编译之 lunch命令分析及user和userdebug编译选项区别

    不同厂商在编译Android系统时 会选择不同产品和编译版本 在Android编译过程中 通过source lunch来选择 1 souuce build envsetup sh 加载命令 2 lunch 选择平台等编译选项 3 make
  • oracle下字段拆分,字段合并的一种方式

    在数据库处理中 我遇到了设计很让人蛋疼的表 此表处理一对多关系的方式是 将一个主键对应的多个值用逗号分割 然后存放在一个字段中 于是 我在表中遇到了类似这样的数据 表A id val 1 kate jam lucy tracy 2 jim
  • 【正则表达式04】匹配多个字符

    xyz xyz为普通字符 不是元字符 把xyz当做一个整体去匹配 x 匹配 0 个或者 1 个 x x 匹配 0 个或者任意多个 x 匹配0个或者任意多个字符 换行符除外 x 匹配至少 1 个 x x n 匹配n个x n是非负整数 x n
  • 如何通过没有直接关系的参数关联两个事物

    通过没有直接关系的参数关联两个事物 可以采用以下几种方法 统计分析 通过收集大量数据 使用统计方法发现两个事物之间的相关性 虽然两个事物之间可能没有直接的因果关系 但通过收集和分析大量的数据 可以发现它们之间存在间接的相关性 可视化分析 通
  • SaltStack 企业级自动化运维实战

    一 SaltStack 概述 1 SaltStack 简介 SaltStack是一个服务器基础架构集中化管理平台 具备配置管理 远程执行 监控等功能 一般可以理解为简化版的puppet和加强版的func SaltStack基于Python语
  • 我是一个线程

    第一回 初生牛犊 我是一个线程 我一出生就被编了个号 0x3704 然后被领到一个昏暗的屋子里 在这里我发现了很多和我一模一样的同伴 我身边的同伴0x6900 待的时间比较长 他带着沧桑的口气对我说 我们线程的宿命就是处理包裹 把包裹处理完
  • 给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 的那 两个 整数,并返回它们的数组下标。 你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案...

    给定一个整数数组 nums 和一个整数目标值 target 要求在数组中找出两个整数 使得它们的和为目标值 并返回它们的数组下标 你可以假设每种输入只会对应一个答案 且同一个元素在答案中不能重复出现 你可以按任意顺序返回答案 例如 给定 n
  • Jenkins配置邮件发送测试报告

    我们用jenkins集成测试 Jenkins GitLab Python自动化测试持续集成 构建任务执行完成后 可以将测试结果通过邮件形式发送至相关人员 告知本次项目构建结果 一 开启邮箱SMTP服务 这里我用的是网易163邮箱 登录163
  • Unity 实现 角色的换装

    换装的三个要点 材质 网格 模型 unity中换装 即更改角色部位上的skinnedMeshRender组件的属性 更换mesh mesh 和骨骼的重新绑定 最后更换材质 一个模型 带有skinnedMeshRender组件 的子节点 和对
  • 灰灰-328-LeetCode682棒球比赛(vector、stack、atio()、substr()、c_str()、accumulate())

    你现在是棒球比赛记录员 给定一个字符串列表 每个字符串可以是以下四种类型之一 1 整数 一轮的得分 直接表示您在本轮中获得的积分数 2 一轮的得分 表示本轮获得的得分是前两轮有效 回合得分的总和 3 D 一轮的得分 表示本轮获得的得分是前一
  • SQLPro Studio for Mac(可视化数据库管理工具)

    SQLPro Studio for Mac是一款可视化数据库管理工具 为创建 MySQL MSSQL Oracle和Postgres连接提供支持的数据库管理解决方案 包括SSH隧道功能 SQLPro Studio为您提供了通过相同的用户界面
  • 华为免费虚拟服务器,免费试用虚拟服务器

    免费试用虚拟服务器 内容精选 换一换 本节操作介绍切换虚拟私有云的操作步骤 仅支持单网卡切换虚拟私有云 切换虚拟私有云会导致云服务器网络中断 切换虚拟私有云过程中 请勿操作云服务器的弹性公网IP 或对云服务器做其他操作 切换虚拟私有云后 云
  • OpenCV

    OpenCV Mat类的copyT clone 赋值的区别 1 clone 2 copyTo 3 等号 赋值 4 验证 先说一下Mat类的结构 Mat类我们可以分成两部分 头部分 矩阵数据部分 头部分 用于记录矩阵数据的大小 类型 数据指针
  • 遗传算法的概念和python实现

    遗传算法是一个非常经典的智能算法 主要用于解决优化问题 本文主要简单介绍一些原理 同时给出一个基于python实现的 用于解决实数内优化问题的模板 本文参考 原理 遗传算法入门详解 知乎 简单介绍 遗传算法就是借鉴生物学中的遗传 首先生成若