# 线性拟合

一个表达式可以拟合的曲线由算子的特征决定,在进行线性拟合时我们希望表达式可以表现出线性特征,所以选择基本算子即可,另附加选择自然常数 E 辅助常量生成。

提示

请注意,虽然 gepjs 可以处理线性拟合,但这仅是近似处理,能拟合什么样的曲线与选择的算子有很大关系。

在整个进化过程中,有可能会出现非线性的结果,这是由于 */ 两个算子连用可能会出现非线性结果,虽然精英策略可以帮助我们保留尽可能满足要求的个体,但这并不能排除所有偶然情况。

在一些特殊场景下,线性回归的结果可能不会完全满足预期,其中有一些场景是数据所决定的,如:

  • 数据区段太短,没有明显的线性特征;
  • 数据噪点跳动太大,掩盖了线性特征;

另一些情况,可能是算子或环境参数设置导致的,例如:

  • 头部太长,导致 */ 两个算子可以被连续表达;
  • 选择了其他的非线性算子,例如 sinpow 等;

所以,在线性拟合中,建议使用基本算子作为 函数符,再增加几个基本质数和自然常数辅助常量或者系数生成,头部长度尽量不要太长。

# 数据生成

在本节示例中,测试数据由下面的函数生成:

// 随机生成系数 k 和常量 b
const k = Math.random() * 4.13 - Math.random() * 1.68;
const b = Math.random() * 12.345;
// f(x):
const y = k * x + b + Math.random() * noise * k;

# 输入参数

模型接收一个 x 作为入参 终止符

符号 类型 说明
x Number X轴坐标

# 集合算子

符号 表达式
+ a + b
- a - b
* a * b
/ a / b
H a / 2
T a / 3
E 常数 E

使用 Operator 模块设置入参和算子:

import { Operator } from 'gepjs';

const operators = new Operator();
// 清空内建算子
operators.clear();

// 设置新算子
operators.setFunc('+', (a, b) => a + b);
operators.setFunc('-', (a, b) => a - b);
operators.setFunc('*', (a, b) => a * b);
operators.setFunc('/', (a, b) => a / b);
operators.setFunc('H', (a) => a / 2);
operators.setFunc('T', (a) => a / 3);
operators.setFunc('E', () => Math.E);
// 设置入参变量
operators.setVars('x');

// 导出数组以便环境使用
const operSets = operators.toArray();

# 环境参数:

在这个示例中,为了尽可能确保结果是线性的,头部长度被设置为 3 ,这样一来就能排除大多数 */ 算子连续表达的基因,确保拟合结果尽可能是线性的。

头部长度 突变率 混入率 修正因子
3 0.3 0.3 0.001

# 遗传参数

由于环境参数中基因的头部长度只有 3 ,显的非常短,为了确保整个基因能顺利表达出系数 k ,可以将 Gene shape 设置为 [1, 6] ,这样可以增加基因的长度,有助于表达系数。

种群 染色体长度 Gene Shape 损失函数 迭代数
50 1 [1, 6] Loss.absolute_mean 500

# 可视化

点击下方开始按钮查看动态拟合过程。

表达式:

Click the "Start" button to start calculating the expression

点击下方按钮开始执行

开始拟合