基于遗传编程的符号回归

news2024/11/20 1:45:08

0 前言

作为一种监督学习方法,符号回归(symbolic regression)试图发现某种隐藏的数学公式,以此利用特征变量预测目标变量。

符号回归的具体实现方式是遗传算法(genetic algorithm)。一开始,一群未经历选择的公式会被随机生成。此后的每一代中,最「合适」的公式们将被选中。随着迭代次数的增长,不断繁殖、变异、进化,从而不断逼近数据分布的真相。

函数表示方法(Representation)

假设有两个特征 X 0 X_0 X0 X 1 X_1 X1,需要预测目标 y y y。一个可能随机产生的公式是:

y = X 0 2 − 3 × X 1 + 0.5 y = X_0^2 - 3 × X_1 + 0.5 y=X023×X1+0.5

也可以写作:

y = X 0 × X 0 − 3 × X 1 + 0.5 y = X_0 × X_0 - 3 × X_1 + 0.5 y=X0×X03×X1+0.5

同时,把它转化成一个 S-表达式:
y = ( + ( − ( × X 0 X 0 ) ( × 3 X 1 ) ) 0.5 ) y = (+(-(×X_0X_0)(×3X_1))0.5) y=(+((×X0X0)(×3X1))0.5)

把这个公式表示成一棵语法树,其中函数是内部节点,用深蓝色表示,而变量和常量构成叶节点,用浅蓝色表示。

对于 GP 来说很重要的一点是,公式中的例如 X 0 × X 0 X_0 × X_0 X0×X0 子表达式,或者树中的任意子树,都能够被任意有效的表达所替换

事实上,在程序中,需要进一步简化 S-表达式 并且去掉所有的括号:
y = + − × X 0 X 0 × 3 X 1 0.5 y = +-×X_0X_0×3X_10.5 y=+×X0X0×3X10.5

有了上述这个表达式,就可以递归的实现这棵二叉树,底层主要是利用栈实现。(Python 中可以利用列表实现)

个体评价:适应度(Fitness)

和其他机器学习算法一样,遗传算法的核心在于衡量公式的适应度(fitness function)。在符号回归里,适应度的地位类似于目标函数、score、loss 和 error。

gplearn 的主要组成部分有两个:SymbolicRegressor 和 SymbolicTransformer。两者的适应度有所不同。

SymbolicRegressor 是回归器。它利用遗传算法得到的公式,直接预测目标变量的值。

SymbolicTransformer是转换器。它并不直接预测目标变量,而是转化原有的特征、输出新的特征,这在特征工程的阶段尤为有效。

SymbolicRegressor的适应度有三种,都是机器学习里常见的 error function:

  • mae: mean absolute error
  • mse: mean squared error
  • rmse: root mean squared error

SymbolicTransformer 会最大化输出的新特征与目标变量之间的相关系数的绝对值:(并非相关系数本身,因为很大的负相关反而有利于预测)

  • pearson:皮尔逊积矩相关系数(Pearson product-moment correlation coefficient),默认设置。因为它衡量线性相关度,所以适用于下一个预测器(分类或回归)是线性模型的情况。
  • spearman:斯皮尔曼等级相关系数(Spearman’s rank correlation coefficient)。因为它衡量单调相关度,所以适用于下一个预测器(分类或回归)是决策树类模型的情况。

当然,用户也可以自定义适应度的标准。

遗传算法内,耗时最大的部分无疑是适应度的计算。所以,gplearn允许用户通过修改n_jobs参数控制并行运算。在数据量和公式数量较大时,并行计算的速度优势最为明显。

特殊情况限制

因为输入值很可能是随机产生的,所以这些函数需要处理诸如「除以零」的问题。因此,gplearn 中的许多函数并不符合它们原本的数学定义,而是「受保护」的修改版:

  • 除法的分布在 -0.001 到 0.001 之间,则返回 1
  • 平方根下的式子取绝对值 ∣ a ∣ \sqrt{|a|} a
  • log 的参数也取绝对值 l o g a ∣ b ∣ log_a|b| logab,或者当参数小于 0.001,直接返回 1
  • 如果一个数在 -0.001 到 0.001 之间,则它的倒数返回零。

对目标变量进行标准化(standardization)和区间缩放(min-max-scaling)可以有效避免常数值区间不符的问题。

个体初始化(Initialization)

当执行一个遗传编程算法的实时,第一代并不知道需要最大化那一种表达式,通常是随机任意的将变量和函数进行混合,这样普遍会得到比较差的效果,这个时候可以通过人为的提供一个较好的初始化参数来初始化种群,从而增加算法性能,其中最重要的一个影响因素是,数据集的特征数量。

第一个要注重的参数是初始化数的深度 init_depth ,init_depth 是一个表示范围的整数二元组,第一代的深度,在这个范围内随机产生。默认 2-6 的范围通常是一个很好的起点,但是如果数据集有很多特征,可以把这个范围扩大,深度加深。

接下来要考虑的参数为种群的大小,如果特征比较少,并且函数集比较少,可以初始化一个较小的种群,相反,初始化一个交大的种群。

最后,需要决定出适合数据集的方法 init_method,'grow', 'full', or 'half and half' 中的一个

  • grow: 公式树从根节点开始生长。在每一个子节点,gplearn 会从所有常数、变量和函数中随机选取一个元素。如果它是常数或者变量,那么这个节点会停止生长,成为一个叶节点。如果它是函数,那么它的两个子节点将继续生长。用 grow 策略生长得到的公式树往往不对称,而且普遍会比用户设置的最大深度浅一些
  • full: 从函数集中选择作为内部节点,直到达到最大深度,然后再选择从常数或者变量中选择叶节点。倾向于生长对称的满树。
  • half and half: 一般的种群执行 ‘grow’ 方法,另一半的种群执行 ‘full

个体选择(Selection)

现在需要决定哪些种群将被进化到下一代。在 gplearn 中,是通过锦标赛完成的。从群体中随机选择一个较小的子集进行竞争,其规模由 tournament_size 参数控制。然后在这个子集中选择适应的最好的公式进入下一代。

锦标赛中,当设置一个较大的 tournament_size ,通常会更快地找到更合适的公式,进化过程将倾向于在更短的时间内收敛到一个解决方案。较小的 tournament_size 可能会在群体中保持更多的多样性,因为更多的公式被给予了进化的机会,而且群体可能会以花费更长时间为代价找到更好的解决方案。这被称为选择压力,选择可能受计算时间的制约。

交叉(Crossover)

优胜者内随机选择一个子树,替换为另一棵公式树的随机子树。此处的另一棵公式树通常是剩余公式树中适应度最高的。

变异

子树变异(Subtree Mutation)

由 p_subtree_mutation 参数控制。这是一种更激进的变异策略:优胜者的一棵子树将被另一棵完全随机的全新子树代替。

hoist 变异(Hoist Mutation)

由 p_hoist_mutation 参数控制。hoist 变异是一种对抗公式树膨胀(bloating,即过于复杂)的方法:从优胜者公式树内随机选择一个子树 A ,再从 A 里随机选择一个子树 B,然后把 B 提升到 A 原来的位置,用 B 替代 A。hoist 的含义即「升高、提起」。

点变异(Point Mutation)

由 p_point_replace 参数控制。一个随机的节点将会被改变,比如加法可以被替换成除法,变量 X0 可以被替换成常数 -2.5。点变异可以重新加入一些先前被淘汰的函数和变量,从而促进公式的多样性。

由于进化过程的黑箱属性,调参很大程度上依赖于用户的直觉和经验。对于实际问题本身的理解也必不可少,如:最终的公式可能有多复杂?

在使用 SymbolicRegressor 时,对目标变量进行标准化(standardization)和区间缩放(min-max-scaling)可以有效避免常数值区间不符的问题。(假如目标变量的区间是 [-1000, 4000],那么区间为 [-1, 1] 的常数恐怕不会有多大帮助,最终得出的公式只会是一串几乎毫无意义的加法和乘法。)

迭代终止(Termination)

有两种方式可以使进化过程停止。第一种是达到由参数 generation 控制的最大迭代数。第二种方式是,种群中至少有一个公式的适应度超过了某个阈值。如果在处理现实生活中的数据,可能需要做一些测试运行来确定阈值的选择。

膨胀现象(Bloat)

一棵公式树的复杂度有两个方面:深度(树的深度)和长度(节点的总数量)。当公式变得越来越复杂,计算速度也越发缓慢,但它的适应度却毫无提升时,我们称这种现象为膨胀(bloating)。

对抗膨胀的方法如下:

在适应度函数中加入节俭系数(parsimony coefficient),由参数 parsimony_coefficient 控制,惩罚过于复杂的公式。节俭系数往往由实践验证决定。如果过于吝啬(节俭系数太大),那么所有的公式树都会缩小到只剩一个变量或常数;如果过于慷慨(节俭系数太小),公式树将严重膨胀。不过,gplearn 已经提供了 ‘auto’ 的选项,能自动控制节俭项的大小。
使用 hoist 变异,削减过大的公式树。
每一代的进化中,只有一部分样本会被随机选取,用于衡量公式的适应度。此处样本的数量由参数 max_samples 控制。这种做法不仅提升了运算速度、保证了公式的多样性,还允许用户查看每一个公式的 out-of-bag fitness,更为客观。

tips:

  1. 遗传编程和遗传规划或遗传程序设计是指代同一类(Genetic Programming,GP)
  2. 基因表达式编程(Gene Expression Programming, GEP, 2001 年 F. Candida 提出)

Reference

[1] gplearn 官方文档: https://gplearn.readthedocs.io/en/stable/intro.html#closure

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/110636.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数字三角形问题

数字三角形问题一、题目描述二、题目分析1、问题分析2、思路分析(1)状态转移方程状态表示状态转移(2)循环的设计三、代码实现一、题目描述 二、题目分析 1、问题分析 这道题给我们的第一眼感觉就是情况太多了,太复杂…

虚拟化环境下,如何高效开展勒索病毒防护加固?

本文重点 近些年,勒索病毒攻击事件频发,由于其“难发现、难阻止、难破解”的特点,不少用户——尤其是使用虚拟化的金融、医疗、制造、公共服务等重要行业用户——已遭受严重数据与经济损失。勒索攻击的防控是一项系统性工程,除了…

2-2-3-9-1-1、jdk1.7HashMap详解

目录数据结构链表的作用链表问题数据结构简图源码解析重要成员变量说明构造函数put操作初始化数组Key为null的处理计算hash添加链表节点--新增Entry扩容缺点扩容死锁分析单线程扩容多线程扩容数据结构 jdk1.7的hashmap的底层结构是数组加单向链表实现的。将key的hash值进行取模…

深度学习环境搭建

深度学习环境搭建0.引言1.Jupyter Notebook1.1.ANACONDA安装1.2.基于conda安装Jupyter Notebook1.3.Jupyter Notebook使用2.Pycharm2.1.安装Pycharm2.2.Pycharm设置0.引言 一步步采坑更新。 1.Jupyter Notebook 官方文档 安装参考 通过安装Anaconda来解决Jupyter Notebook…

300行HTML+CSS+JS代码实现动态圣诞树

文章目录1. 前言2. 效果展示3. 准备🍑 下载编译器🍑 下载插件4. 源码🍑 HTML🍑 JS🍑 CSS5. 结语1. 前言 一年一度的圣诞节和考研即将来临,那么这篇文章将用到前端三大剑客 HTML CSS JS 来实现动态圣诞树…

Java面试题(六)多线程经典编程题

经典的多线程编程题猜数字游戏键盘输入练习3个线程轮流打印ABC多窗口买票猜数字游戏 题目说明:有2个线程,第一个线程A随机一个100内的数,第2个线程B来猜,B每次猜一个数后A会判断,如果猜对了程序结束,如果猜…

工具在接口测试中发挥什么样的作用?

接口测试究竟是什么?为什么要用接口测试?它有哪些工具呢?这一连串的问题敲击着我们,请带着这些问题,在本文中寻找答案,我将为您打开接口测试的大门。 1 初探接口测试 接口测试是什么。它检查数据的交换&…

从《我要投资》,看藏在“对立面”里的创业正解

文|智能相对论 作者|青月 六位07届的快乐男声选手在象山体验养鹅,意外出圈;随后播出的09届超女的怀旧综艺却热度一般,可见只有单纯的情怀消费并不能保证节目的口碑,只有建立在准确的节目定位与恰当的价值输出基础上,…

面试必备:从常见的存储引擎到混淆的锁分类,请上车

今天我们来总结一下MyISAM和InnoDB引擎下锁的种类及使用方法。 MySQL的四大常见存储引擎 谈到MyISAM和InnoDB了我们先来了解一下什么是存储引擎吧。MySQL中的数据用各种不同的技术存储在文件(或者内存)中,这些技术中的每一种技术都使用不同…

m基于贝叶斯理论的超分辨率重构算法matlab仿真,对比Tikhonov重构算法

目录 1.算法描述 2.仿真效果预览 3.MATLAB核心程序 4.完整MATLAB 1.算法描述 超分辨率(Super-Resolution)通过硬件或软件的方法提高原有图像的分辨率,通过一系列低分辨率的图像来得到一幅高分辨率的图像过程就是超分辨率重建。超分辨率成像(SR-imagi…

一个内核oops问题的分析及解决

最近在调试设备时,遇到了一个偶发的开机死机问题。通过查看输出日志,发现内核报告了oops错误,如下所示(中间省略了部分日志,以......代替): Unable to handle kernel NULL pointer dereference…

YOLOV7学习记录之训练过程

在前面学习YOLOV7的过程中,我们已经学习了其网络结构,然而实际上YOLOV7项目的难点并不在于其网络模型而是在于其损失函数的设计,即如何才能训练出来合适的bbox。 神经网络模型都有训练和测试(推理)过程,在Y…

QT JS交互、调用JS、传值

本文详细的介绍了QT JS交互、调用JS、传值的各种操作,包括QT向JS传递String字符串、包括QT向JS传递Int数字、包括QT向JS传递List数组,同时也接收JS向QT返回的List数组、JS向QT返回的Json、JS向QT返回的数字、JS向QT返回的字符串。 本文作者原创&#xff…

Vue基础8之Vue组件化编程、非单文件组件与单文件组件

Vue基础8Vue组件化编程对组件的理解一些概念的理解非单文件组件基本使用几个注意点组件的嵌套VueComponent一个重要的内置关系先导篇:原型对象正文(可以理解为类的继承)单文件组件Vue组件化编程 对组件的理解 传统方式: 使用组…

计算机网络-交换方式

目录电路交换(Circuit Switching)分组交换(Packet Switching)报文交换(Message Switching)电路交换、报文交换、分组交换的对比电路交换(Circuit Switching) 在电话问世后不久&#…

扫雷游戏的设计(百分百还原电脑操作)

目录 🌲了解扫雷游戏的作用原理并梳理思路 🌲扫雷游戏前期部分完善 🌷文件的创建 🌷创建菜单,完善主函数 🌳代码呈现: 🌲扫雷游戏主题内容 🌴第一步初始化棋盘 &#x1…

Gradle中如何修改Springboot引入的依赖版本

扫描漏洞升级 不知道各位是否遇到过以下问题: 当下层项目将spring引入的某个依赖版本升级之后,上层项目只要指定了Springboot版本,那么还是会将这个版本改回去? 比如:现在有两个Springboot项目A、B,B项目…

Git安装和配置

GitGitee 官网安装配置教程:https://gitee.com/help/articles/4104本文是以官网教程为基础而展开的实践笔记。初学者可以以本文为引入,但建议最终以官方文档为最终深入学习的参考。一、 下载和安装Git 1、官网下载:https://git-scm.com 如果对…

HTML5基础

HTML5 文章目录HTML5概述开发工具浏览器开发软件DemoHTML5语法HTML5标签HTML5标签属性HTML5文档注释HTML5文档结构头部内容主体内容DemoHTML5常见标签常见块级标签标题标签水平线标签段落标签换行标签引用标签预格式标签无序列表标签有序列表标签定义列表标签分区标签常见行级标…

【Java寒假打卡】Java基础-继承

【Java寒假打卡】Java基础-继承一、继承的好处和弊端二、继承的成员变量访问特点三、重写方法四、方法重写的注意事项五、权限修饰符六、构造方法一、继承的好处和弊端 继承的好处 提高了代码的复用性 提高了代码的维护性 让类和类之间产生了关系 是多态的前提 继承的弊端 …