moc / math
PHP数学拟合库。执行数据的线性和非线性拟合。包括拟合时使用的各种数学类。包含大量的线性代数,如矩阵和向量代数。
This package is not auto-updated.
Last update: 2024-09-14 15:28:37 UTC
README
PHP数学库。包括矩阵操作、方程求解以及线性和非线性拟合
一些矩阵计算也可以使用PHP的lapack扩展完成。MOC/Math包是一个原生PHP实现,速度可能较慢,但不需要任何外部库。
该库功能尚未完善,仅包含进行线性和非线性拟合所需的最基本功能。算法灵感来源于非常优秀的书籍《数值食谱》。
安装
最简单的方法是使用composer将其包含在现有的composer项目中。
composer require moc/math
然后您可以直接在项目中使用它。
<?php require_once __DIR__ . '/vendor/autoload.php'; use \MOC\Math\DataSeries; $data = DataSeries::fromArray(array( array(0, 1.0, 0.1), array(1, 1.5, 0.2), array(2, 3.0, 0.09), array(3, 4.8, 0.11), array(4, 6.1, 0.15) )); foreach ($data as $point) { printf("X: %4.2f\tY: %4.2f\n", $point->getX(), $point->getY()); }
矩阵和向量
矩阵类使用二维行优先数组构建。示例
$matrix = new Matrix(array( array(1, 2, 5), array(5, 2, 7), array(3, 9, 2) ));
矩阵还有两个工厂类,用于创建空和单位矩阵
$identity = Matrix::identity(2)
将创建对角线元素为1,其余元素为0的2x2矩阵
$empty = Matrix::emptyMatrix(2,2)
将创建所有元素都设置为0的2x2矩阵。
矩阵类包括以下方法
- multiplyWithVectorFromRight
- equals
- getInverse
向量类通过以下方式构建
$vector = new Vector(array(2,3,4);
并包括寻找范数、长度等方法。
数据系列和点
Point类表示XY平面上的一个单独的点,可能附有一个误差。
要创建x=0,y=1的点,带有一个可选误差0.5,使用此方法
$point = new \MOC\Math\Point(array(0.00, 1.00, 0.5);
DataSeries对象用于包含一系列数据点。它的构造函数接受点对象的数组,但它还包含从数组创建数据系列的方便的工厂方法。
$data = DataSeries::fromArray(array( array(0, 1.0), array(1, 1.5), array(2, 3.0), array(3, 4.8), array(4, 6.1) ));
每个点都附加了误差
$data = DataSeries::fromArray(array( array(0, 1.0, 0.1), array(1, 1.5, 0.2), array(2, 3.0, 0.09), array(3, 4.8, 0.11), array(4, 6.1, 0.15) ));
数据系列实现了countable、ArrayAccess和Iterator,因此可以使用如下方式
foreach ($data as $point) { // Do stuff with $point which is now a \MOC\Math\Point object } print count($data); print "Point 2: " . $data[2]->getY();
高斯-若尔当消元法
还包括一个用于对角化矩阵的高斯-若尔当消元算法实现。这在求解逆矩阵、解M未知数N个方程或拟合数据到模型数据时很有用。
$solver = new \MOC\Math\GaussJordan(); $solver->solve($matrixA, $matrixB);
注意,solve方法实际上会更改矩阵$matrixA和$matrixB。$matrixB必须有与$matrixA相同的行数,否则会抛出异常。
调用solve后,$matrixA将是单位矩阵,所有使$matrixA成为此矩阵的操作也将应用于$matrixB。因此,如果$matrixA是一个方阵且$matrixB是单位矩阵,对solve的调用将使$matrixB成为$matrixA的逆矩阵。
该算法使用部分主元选择。
线性回归或线性最小二乘
Math包的主要目的是提供一个拟合引擎,用于将数据集拟合到给定的模型。其中一部分是线性回归,其中数据被拟合到一个可以用基函数的线性组合来描述的模型。单个基函数在x上可以非线性变化,但不能依赖于参数。
示例
将数据集拟合到函数y(x) = a + bx + cx^2
单个基函数是1、x和x^2,我们希望找到参数a、b、c,使得模型通过最小二乘线性回归最佳拟合我们的数据。
这可以通过调用LinearFitingEngine来完成
<?php require_once __DIR__ . '/vendor/autoload.php'; use \MOC\Math\DataSeries; use \MOC\Math\Fitting\LinearFittingEngine; use \MOC\Math\MathematicalFunction\Polynomial; $data = DataSeries::fromArray(array( array(0, 1.0), array(1, 1.5), array(2, 3.0), array(3, 4.8), array(4, 6.1) )); $functionToFitTo = new Polynomial(2); $fitter = new LinearFittingEngine($data, $functionToFitTo); $fitter->fit(); print "Result: " . $functionToFitTo . PHP_EOL; // Will render the function with is parameters print 'Parameters: ' . PHP_EOL; print_r($functionToFitTo->getParameters()) . PHP_EOL; print 'Chi^: ' . $fitter->getChiSquared() . PHP_EOL;
实际的求解是通过带有全主元选择的高斯-若尔当消元法完成的。这的缺点是矩阵对角化可能会遇到零主元元素,导致奇异矩阵。在这种情况下,将抛出异常。
我们可以实现一个处理这种情况更好的奇异值分解算法。这已经在待办事项列表中。
请注意,单独的点也可以设置误差,这将影响考虑这些误差的拟合算法。
$data = \MOC\Math\DataSeries::fromArray(array( array(0, 1.0, 0.1), array(1, 1.5, 0.2), array(2, 3.0, 0.09), array(3, 4.8, 0.11), array(4, 6.1, 0.15) ));
非线性回归或非线性最小二乘法
将数据拟合到非线性的模型需要不同的方法。而是需要一个迭代解决方案。从一个参数值开始,计算卡方值。然后使用Levenberg-Marquardt方法以智能的方式调整参数,重新计算卡方值。如果拟合更好,则保留这些参数,否则尝试另一组参数。继续这样做,直到卡方值达到最小。最小值可能不是全局最小值,因此,开始时参数的初始值应接近期望值非常重要。
此库还提供了解决此类问题的求解器。
求解器更容易出错,并且需要拟合的函数需要用变量的“最佳猜测”初始化,否则您可能会达到一个局部最小值,这并不是数据的最佳拟合。
示例
将数据序列拟合到由y(x) = a + b*exp(- ((x-c)/d)^2)描述的高斯函数,这正是这种问题。它也可以是(有限个)高斯函数的和,但这个例子只是单个高斯函数。高斯函数是通过实现NonLinearFittingEngine所需的NonLinearCombinationOfFunctions接口的\MOC\Math\MathematicalFunction\GaussianFunction实现的
<?php require_once __DIR__ . '/vendor/autoload.php'; use \MOC\Math\DataSeries; use \MOC\Math\Fitting\NonLinearFittingEngine; use \MOC\Math\MathematicalFunction\GaussianFunction; $data = DataSeries::fromArray(array( array(0.5, 0.25, 0.05), array(1.13, 0.7, 0.10), array(1.6, 1.8, 0.12), array(2.0, 2.8, 0.09), array(2.5, 1.8, 0.04), array(3.0, 0.7, 0.001), array(3.5, 0.2, 0.01) )); $functionToFitTo = new GaussianFunction(); // Do a best guess on the parameters on basis of the dataset. $bestGuess = array (0, 1.8, 1.8, 1); $functionToFitTo->setParameters($bestGuess); // In this example, we only solve for the b,c and d parameters, we keep the a fixed. $fitter = new NonLinearFittingEngine($data, $functionToFitTo, array(FALSE, TRUE, TRUE, TRUE)); $fitter->fit(); print 'Result: ' . $functionToFitTo . PHP_EOL; // Will render the function with is parameters print 'Parameters: ' . PHP_EOL; print_r($functionToFitTo->getParameters()) . PHP_EOL; print 'Chi^2: ' . $fitter->getChiSquared() . PHP_EOL; print 'Iterations: ' . $fitter->getNumberOfIterations() . PHP_EOL;
在范围内评估函数
该库包含一些评估区间内函数的实用函数,当可视化数据时很有用。
<?php require_once __DIR__ . '/vendor/autoload.php'; use \MOC\Math\DataSeries; use \MOC\Math\MathematicalFunction\Polynomial; $function = new \MOC\Math\Polynomial(2); $function->setParameters(array(0.00, 1, 1)); $data = \MOC\Math\MathUtility::evaluateFunctionInInterval($function, -2.0, 2.0, 100); // Evalute from -2 to 2 in 100 steps foreach ($data as $point) { printf("X: %4.2f\tY: %4.2f\n", $point->getX(), $point->getY()); }