# 线性拟合
一个表达式可以拟合的曲线由算子的特征决定,在进行线性拟合时我们希望表达式可以表现出线性特征,所以选择基本算子即可,另附加选择自然常数 E 辅助常量生成。
提示
请注意,虽然 gepjs 可以处理线性拟合,但这仅是近似处理,能拟合什么样的曲线与选择的算子有很大关系。
在整个进化过程中,有可能会出现非线性的结果,这是由于 *
和 /
两个算子连用可能会出现非线性结果,虽然精英策略可以帮助我们保留尽可能满足要求的个体,但这并不能排除所有偶然情况。
在一些特殊场景下,线性回归的结果可能不会完全满足预期,其中有一些场景是数据所决定的,如:
- 数据区段太短,没有明显的线性特征;
- 数据噪点跳动太大,掩盖了线性特征;
另一些情况,可能是算子或环境参数设置导致的,例如:
- 头部太长,导致
*
和/
两个算子可以被连续表达; - 选择了其他的非线性算子,例如
sin
、pow
等;
所以,在线性拟合中,建议使用基本算子作为 函数符,再增加几个基本质数和自然常数辅助常量或者系数生成,头部长度尽量不要太长。
# 数据生成
在本节示例中,测试数据由下面的函数生成:
// 随机生成系数 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
点击下方按钮开始执行