Trend unit tests (#1899)

- Move TREND() functions into the Statistical Trends class
- Unit tests for TREND()
- Create Confidence class for Statistical Confidence functions
This commit is contained in:
Mark Baker 2021-03-06 22:50:19 +01:00 committed by GitHub
parent a79a4ddbab
commit 2d8c8c8ecf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 344 additions and 111 deletions

View File

@ -226,7 +226,7 @@ class Trends
], ],
[ [
$bestFitLinear->getSlopeSE(), $bestFitLinear->getSlopeSE(),
$bestFitLinear->getIntersectSE(), ($const === false) ? Functions::NA() : $bestFitLinear->getIntersectSE(),
], ],
[ [
$bestFitLinear->getGoodnessOfFit(), $bestFitLinear->getGoodnessOfFit(),
@ -293,7 +293,7 @@ class Trends
], ],
[ [
$bestFitExponential->getSlopeSE(), $bestFitExponential->getSlopeSE(),
$bestFitExponential->getIntersectSE(), ($const === false) ? Functions::NA() : $bestFitExponential->getIntersectSE(),
], ],
[ [
$bestFitExponential->getGoodnessOfFit(), $bestFitExponential->getGoodnessOfFit(),

View File

@ -348,13 +348,13 @@ class BestFit
$bestFitY = $this->yBestFitValues[$xKey] = $this->getValueOfYForX($xValue); $bestFitY = $this->yBestFitValues[$xKey] = $this->getValueOfYForX($xValue);
$SSres += ($this->yValues[$xKey] - $bestFitY) * ($this->yValues[$xKey] - $bestFitY); $SSres += ($this->yValues[$xKey] - $bestFitY) * ($this->yValues[$xKey] - $bestFitY);
if ($const) { if ($const === true) {
$SStot += ($this->yValues[$xKey] - $meanY) * ($this->yValues[$xKey] - $meanY); $SStot += ($this->yValues[$xKey] - $meanY) * ($this->yValues[$xKey] - $meanY);
} else { } else {
$SStot += $this->yValues[$xKey] * $this->yValues[$xKey]; $SStot += $this->yValues[$xKey] * $this->yValues[$xKey];
} }
$SScov += ($this->xValues[$xKey] - $meanX) * ($this->yValues[$xKey] - $meanY); $SScov += ($this->xValues[$xKey] - $meanX) * ($this->yValues[$xKey] - $meanY);
if ($const) { if ($const === true) {
$SSsex += ($this->xValues[$xKey] - $meanX) * ($this->xValues[$xKey] - $meanX); $SSsex += ($this->xValues[$xKey] - $meanX) * ($this->xValues[$xKey] - $meanX);
} else { } else {
$SSsex += $this->xValues[$xKey] * $this->xValues[$xKey]; $SSsex += $this->xValues[$xKey] * $this->xValues[$xKey];
@ -362,7 +362,7 @@ class BestFit
} }
$this->SSResiduals = $SSres; $this->SSResiduals = $SSres;
$this->DFResiduals = $this->valueCount - 1 - $const; $this->DFResiduals = $this->valueCount - 1 - ($const === true ? 1 : 0);
if ($this->DFResiduals == 0.0) { if ($this->DFResiduals == 0.0) {
$this->stdevOfResiduals = 0.0; $this->stdevOfResiduals = 0.0;
@ -395,27 +395,39 @@ class BestFit
} }
} }
private function sumSquares(array $values)
{
return array_sum(
array_map(
function ($value) {
return $value ** 2;
},
$values
)
);
}
/** /**
* @param float[] $yValues * @param float[] $yValues
* @param float[] $xValues * @param float[] $xValues
* @param bool $const
*/ */
protected function leastSquareFit(array $yValues, array $xValues, $const): void protected function leastSquareFit(array $yValues, array $xValues, bool $const): void
{ {
// calculate sums // calculate sums
$x_sum = array_sum($xValues); $sumValuesX = array_sum($xValues);
$y_sum = array_sum($yValues); $sumValuesY = array_sum($yValues);
$meanX = $x_sum / $this->valueCount; $meanValueX = $sumValuesX / $this->valueCount;
$meanY = $y_sum / $this->valueCount; $meanValueY = $sumValuesY / $this->valueCount;
$mBase = $mDivisor = $xx_sum = $xy_sum = $yy_sum = 0.0; $sumSquaresX = $this->sumSquares($xValues);
$sumSquaresY = $this->sumSquares($yValues);
$mBase = $mDivisor = 0.0;
$xy_sum = 0.0;
for ($i = 0; $i < $this->valueCount; ++$i) { for ($i = 0; $i < $this->valueCount; ++$i) {
$xy_sum += $xValues[$i] * $yValues[$i]; $xy_sum += $xValues[$i] * $yValues[$i];
$xx_sum += $xValues[$i] * $xValues[$i];
$yy_sum += $yValues[$i] * $yValues[$i];
if ($const) { if ($const === true) {
$mBase += ($xValues[$i] - $meanX) * ($yValues[$i] - $meanY); $mBase += ($xValues[$i] - $meanValueX) * ($yValues[$i] - $meanValueY);
$mDivisor += ($xValues[$i] - $meanX) * ($xValues[$i] - $meanX); $mDivisor += ($xValues[$i] - $meanValueX) * ($xValues[$i] - $meanValueX);
} else { } else {
$mBase += $xValues[$i] * $yValues[$i]; $mBase += $xValues[$i] * $yValues[$i];
$mDivisor += $xValues[$i] * $xValues[$i]; $mDivisor += $xValues[$i] * $xValues[$i];
@ -426,13 +438,9 @@ class BestFit
$this->slope = $mBase / $mDivisor; $this->slope = $mBase / $mDivisor;
// calculate intersect // calculate intersect
if ($const) { $this->intersect = ($const === true) ? $meanValueY - ($this->slope * $meanValueX) : 0.0;
$this->intersect = $meanY - ($this->slope * $meanX);
} else {
$this->intersect = 0;
}
$this->calculateGoodnessOfFit($x_sum, $y_sum, $xx_sum, $yy_sum, $xy_sum, $meanX, $meanY, $const); $this->calculateGoodnessOfFit($sumValuesX, $sumValuesY, $sumSquaresX, $sumSquaresY, $xy_sum, $meanValueX, $meanValueY, $const);
} }
/** /**
@ -440,23 +448,22 @@ class BestFit
* *
* @param float[] $yValues The set of Y-values for this regression * @param float[] $yValues The set of Y-values for this regression
* @param float[] $xValues The set of X-values for this regression * @param float[] $xValues The set of X-values for this regression
* @param bool $const
*/ */
public function __construct($yValues, $xValues = [], $const = true) public function __construct($yValues, $xValues = [])
{ {
// Calculate number of points // Calculate number of points
$nY = count($yValues); $yValueCount = count($yValues);
$nX = count($xValues); $xValueCount = count($xValues);
// Define X Values if necessary // Define X Values if necessary
if ($nX == 0) { if ($xValueCount === 0) {
$xValues = range(1, $nY); $xValues = range(1, $yValueCount);
} elseif ($nY != $nX) { } elseif ($yValueCount !== $xValueCount) {
// Ensure both arrays of points are the same size // Ensure both arrays of points are the same size
$this->error = true; $this->error = true;
} }
$this->valueCount = $nY; $this->valueCount = $yValueCount;
$this->xValues = $xValues; $this->xValues = $xValues;
$this->yValues = $yValues; $this->yValues = $yValues;
} }

View File

@ -88,20 +88,17 @@ class ExponentialBestFit extends BestFit
* *
* @param float[] $yValues The set of Y-values for this regression * @param float[] $yValues The set of Y-values for this regression
* @param float[] $xValues The set of X-values for this regression * @param float[] $xValues The set of X-values for this regression
* @param bool $const
*/ */
private function exponentialRegression($yValues, $xValues, $const): void private function exponentialRegression(array $yValues, array $xValues, bool $const): void
{ {
foreach ($yValues as &$value) { $adjustedYValues = array_map(
if ($value < 0.0) { function ($value) {
$value = 0 - log(abs($value)); return ($value < 0.0) ? 0 - log(abs($value)) : log($value);
} elseif ($value > 0.0) { },
$value = log($value); $yValues
} );
}
unset($value);
$this->leastSquareFit($yValues, $xValues, $const); $this->leastSquareFit($adjustedYValues, $xValues, $const);
} }
/** /**
@ -116,7 +113,7 @@ class ExponentialBestFit extends BestFit
parent::__construct($yValues, $xValues); parent::__construct($yValues, $xValues);
if (!$this->error) { if (!$this->error) {
$this->exponentialRegression($yValues, $xValues, $const); $this->exponentialRegression($yValues, $xValues, (bool) $const);
} }
} }
} }

View File

@ -56,9 +56,8 @@ class LinearBestFit extends BestFit
* *
* @param float[] $yValues The set of Y-values for this regression * @param float[] $yValues The set of Y-values for this regression
* @param float[] $xValues The set of X-values for this regression * @param float[] $xValues The set of X-values for this regression
* @param bool $const
*/ */
private function linearRegression($yValues, $xValues, $const): void private function linearRegression(array $yValues, array $xValues, bool $const): void
{ {
$this->leastSquareFit($yValues, $xValues, $const); $this->leastSquareFit($yValues, $xValues, $const);
} }
@ -75,7 +74,7 @@ class LinearBestFit extends BestFit
parent::__construct($yValues, $xValues); parent::__construct($yValues, $xValues);
if (!$this->error) { if (!$this->error) {
$this->linearRegression($yValues, $xValues, $const); $this->linearRegression($yValues, $xValues, (bool) $const);
} }
} }
} }

View File

@ -48,7 +48,7 @@ class LogarithmicBestFit extends BestFit
$slope = $this->getSlope($dp); $slope = $this->getSlope($dp);
$intersect = $this->getIntersect($dp); $intersect = $this->getIntersect($dp);
return 'Y = ' . $intersect . ' + ' . $slope . ' * log(X)'; return 'Y = ' . $slope . ' * log(' . $intersect . ' * X)';
} }
/** /**
@ -56,20 +56,17 @@ class LogarithmicBestFit extends BestFit
* *
* @param float[] $yValues The set of Y-values for this regression * @param float[] $yValues The set of Y-values for this regression
* @param float[] $xValues The set of X-values for this regression * @param float[] $xValues The set of X-values for this regression
* @param bool $const
*/ */
private function logarithmicRegression($yValues, $xValues, $const): void private function logarithmicRegression(array $yValues, array $xValues, bool $const): void
{ {
foreach ($xValues as &$value) { $adjustedYValues = array_map(
if ($value < 0.0) { function ($value) {
$value = 0 - log(abs($value)); return ($value < 0.0) ? 0 - log(abs($value)) : log($value);
} elseif ($value > 0.0) { },
$value = log($value); $yValues
} );
}
unset($value);
$this->leastSquareFit($yValues, $xValues, $const); $this->leastSquareFit($adjustedYValues, $xValues, $const);
} }
/** /**
@ -84,7 +81,7 @@ class LogarithmicBestFit extends BestFit
parent::__construct($yValues, $xValues); parent::__construct($yValues, $xValues);
if (!$this->error) { if (!$this->error) {
$this->logarithmicRegression($yValues, $xValues, $const); $this->logarithmicRegression($yValues, $xValues, (bool) $const);
} }
} }
} }

View File

@ -178,9 +178,8 @@ class PolynomialBestFit extends BestFit
* @param int $order Order of Polynomial for this regression * @param int $order Order of Polynomial for this regression
* @param float[] $yValues The set of Y-values for this regression * @param float[] $yValues The set of Y-values for this regression
* @param float[] $xValues The set of X-values for this regression * @param float[] $xValues The set of X-values for this regression
* @param bool $const
*/ */
public function __construct($order, $yValues, $xValues = [], $const = true) public function __construct($order, $yValues, $xValues = [])
{ {
parent::__construct($yValues, $xValues); parent::__construct($yValues, $xValues);

View File

@ -72,28 +72,23 @@ class PowerBestFit extends BestFit
* *
* @param float[] $yValues The set of Y-values for this regression * @param float[] $yValues The set of Y-values for this regression
* @param float[] $xValues The set of X-values for this regression * @param float[] $xValues The set of X-values for this regression
* @param bool $const
*/ */
private function powerRegression($yValues, $xValues, $const): void private function powerRegression(array $yValues, array $xValues, bool $const): void
{ {
foreach ($xValues as &$value) { $adjustedYValues = array_map(
if ($value < 0.0) { function ($value) {
$value = 0 - log(abs($value)); return ($value < 0.0) ? 0 - log(abs($value)) : log($value);
} elseif ($value > 0.0) { },
$value = log($value); $yValues
} );
} $adjustedXValues = array_map(
unset($value); function ($value) {
foreach ($yValues as &$value) { return ($value < 0.0) ? 0 - log(abs($value)) : log($value);
if ($value < 0.0) { },
$value = 0 - log(abs($value)); $xValues
} elseif ($value > 0.0) { );
$value = log($value);
}
}
unset($value);
$this->leastSquareFit($yValues, $xValues, $const); $this->leastSquareFit($adjustedYValues, $adjustedXValues, $const);
} }
/** /**
@ -108,7 +103,7 @@ class PowerBestFit extends BestFit
parent::__construct($yValues, $xValues); parent::__construct($yValues, $xValues);
if (!$this->error) { if (!$this->error) {
$this->powerRegression($yValues, $xValues, $const); $this->powerRegression($yValues, $xValues, (bool) $const);
} }
} }
} }

View File

@ -55,10 +55,9 @@ class Trend
$nX = count($xValues); $nX = count($xValues);
// Define X Values if necessary // Define X Values if necessary
if ($nX == 0) { if ($nX === 0) {
$xValues = range(1, $nY); $xValues = range(1, $nY);
$nX = $nY; } elseif ($nY !== $nX) {
} elseif ($nY != $nX) {
// Ensure both arrays of points are the same size // Ensure both arrays of points are the same size
trigger_error('Trend(): Number of elements in coordinate arrays do not match.', E_USER_ERROR); trigger_error('Trend(): Number of elements in coordinate arrays do not match.', E_USER_ERROR);
} }
@ -84,7 +83,7 @@ class Trend
case self::TREND_POLYNOMIAL_6: case self::TREND_POLYNOMIAL_6:
if (!isset(self::$trendCache[$key])) { if (!isset(self::$trendCache[$key])) {
$order = substr($trendType, -1); $order = substr($trendType, -1);
self::$trendCache[$key] = new PolynomialBestFit($order, $yValues, $xValues, $const); self::$trendCache[$key] = new PolynomialBestFit($order, $yValues, $xValues);
} }
return self::$trendCache[$key]; return self::$trendCache[$key];
@ -100,7 +99,7 @@ class Trend
if ($trendType != self::TREND_BEST_FIT_NO_POLY) { if ($trendType != self::TREND_BEST_FIT_NO_POLY) {
foreach (self::$trendTypePolynomialOrders as $trendMethod) { foreach (self::$trendTypePolynomialOrders as $trendMethod) {
$order = substr($trendMethod, -1); $order = substr($trendMethod, -1);
$bestFit[$trendMethod] = new PolynomialBestFit($order, $yValues, $xValues, $const); $bestFit[$trendMethod] = new PolynomialBestFit($order, $yValues, $xValues);
if ($bestFit[$trendMethod]->getError()) { if ($bestFit[$trendMethod]->getError()) {
unset($bestFit[$trendMethod]); unset($bestFit[$trendMethod]);
} else { } else {

View File

@ -19,7 +19,7 @@ class LogEstTest extends TestCase
public function testLOGEST($expectedResult, $yValues, $xValues, $const, $stats): void public function testLOGEST($expectedResult, $yValues, $xValues, $const, $stats): void
{ {
$result = Statistical::LOGEST($yValues, $xValues, $const, $stats); $result = Statistical::LOGEST($yValues, $xValues, $const, $stats);
//var_dump($result);
$elements = count($expectedResult); $elements = count($expectedResult);
for ($element = 0; $element < $elements; ++$element) { for ($element = 0; $element < $elements; ++$element) {
self::assertEqualsWithDelta($expectedResult[$element], $result[$element], 1E-12); self::assertEqualsWithDelta($expectedResult[$element], $result[$element], 1E-12);

View File

@ -0,0 +1,49 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Shared\Trend;
use PhpOffice\PhpSpreadsheet\Shared\Trend\ExponentialBestFit;
use PHPUnit\Framework\TestCase;
class ExponentialBestFitTest extends TestCase
{
/**
* @dataProvider providerExponentialBestFit
*
* @param mixed $expectedSlope
* @param mixed $expectedIntersect
* @param mixed $expectedGoodnessOfFit
* @param mixed $yValues
* @param mixed $xValues
* @param mixed $expectedEquation
*/
public function testExponentialBestFit(
$expectedSlope,
$expectedIntersect,
$expectedGoodnessOfFit,
$expectedEquation,
$yValues,
$xValues
): void {
$bestFit = new ExponentialBestFit($yValues, $xValues);
$slope = $bestFit->getSlope(1);
self::assertEquals($expectedSlope[0], $slope);
$slope = $bestFit->getSlope();
self::assertEquals($expectedSlope[1], $slope);
$intersect = $bestFit->getIntersect(1);
self::assertEquals($expectedIntersect[0], $intersect);
$intersect = $bestFit->getIntersect();
self::assertEquals($expectedIntersect[1], $intersect);
$equation = $bestFit->getEquation(2);
self::assertEquals($expectedEquation, $equation);
self::assertSame($expectedGoodnessOfFit[0], $bestFit->getGoodnessOfFit(6));
self::assertSame($expectedGoodnessOfFit[1], $bestFit->getGoodnessOfFit());
}
public function providerExponentialBestFit()
{
return require 'tests/data/Shared/Trend/ExponentialBestFit.php';
}
}

View File

@ -0,0 +1,49 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Shared\Trend;
use PhpOffice\PhpSpreadsheet\Shared\Trend\LinearBestFit;
use PHPUnit\Framework\TestCase;
class LinearBestFitTest extends TestCase
{
/**
* @dataProvider providerLinearBestFit
*
* @param mixed $expectedSlope
* @param mixed $expectedIntersect
* @param mixed $expectedGoodnessOfFit
* @param mixed $yValues
* @param mixed $xValues
* @param mixed $expectedEquation
*/
public function testLinearBestFit(
$expectedSlope,
$expectedIntersect,
$expectedGoodnessOfFit,
$expectedEquation,
$yValues,
$xValues
): void {
$bestFit = new LinearBestFit($yValues, $xValues);
$slope = $bestFit->getSlope(1);
self::assertEquals($expectedSlope[0], $slope);
$slope = $bestFit->getSlope();
self::assertEquals($expectedSlope[1], $slope);
$intersect = $bestFit->getIntersect(1);
self::assertEquals($expectedIntersect[0], $intersect);
$intersect = $bestFit->getIntersect();
self::assertEquals($expectedIntersect[1], $intersect);
$equation = $bestFit->getEquation(2);
self::assertEquals($expectedEquation, $equation);
self::assertSame($expectedGoodnessOfFit[0], $bestFit->getGoodnessOfFit(6));
self::assertSame($expectedGoodnessOfFit[1], $bestFit->getGoodnessOfFit());
}
public function providerLinearBestFit()
{
return require 'tests/data/Shared/Trend/LinearBestFit.php';
}
}

View File

@ -1,6 +1,22 @@
<?php <?php
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
return [ return [
[
[1.0, 0.0],
[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5],
false,
false,
],
[
[2.310344827586207, 0.0],
[1, 9, 5, 7],
[0, 4, 2, 3],
false,
false,
],
[ [
[2.0, 1.0], [2.0, 1.0],
[1, 9, 5, 7], [1, 9, 5, 7],
@ -8,6 +24,46 @@ return [
true, true,
false, false,
], ],
[
[0.600378787879, 0.0],
[3, 10, 3, 6, 8, 12, 1, 4, 9, 14],
[8, 2, 11, 6, 5, 4, 12, 9, 6, 1],
false,
false,
],
[
[-1.1064189189190, 14.081081081081],
[3, 10, 3, 6, 8, 12, 1, 4, 9, 14],
[8, 2, 11, 6, 5, 4, 12, 9, 6, 1],
true,
false,
],
[
[
[0.600378787879, 0.0],
[0.3130441135917, Functions::NA()],
[0.2901220667036, 7.193206086629],
[3.6782360429317, 9],
[190.3200757575760, 465.679924242424],
],
[3, 10, 3, 6, 8, 12, 1, 4, 9, 14],
[8, 2, 11, 6, 5, 4, 12, 9, 6, 1],
false,
true,
],
[
[
[-1.1064189189190, 14.081081081081],
[0.1491074289251, 1.083468383961],
[0.8731378215565, 1.622464237727],
[55.0605598780781, 8],
[144.9408783783780, 21.059121621622],
],
[3, 10, 3, 6, 8, 12, 1, 4, 9, 14],
[8, 2, 11, 6, 5, 4, 12, 9, 6, 1],
true,
true,
],
[ [
[ [
[56.837944664032, 11704.347826086974], [56.837944664032, 11704.347826086974],
@ -21,29 +77,29 @@ return [
true, true,
true, true,
], ],
// [ // 'multi-series' => [
// [ // [
// [-234.2371645, 2553.21066, 12529.76817, 27.64138737, 52317.83051], // [-234.2371645, 2553.21066, 12529.76817, 27.64138737, 52317.83051],
// [13.26801148, 530.6691519, 400.0668382, 5.429374042, 12237.3616], // [13.26801148, 530.6691519, 400.0668382, 5.429374042, 12237.3616],
// [0.996747993, 970.5784629, '#N/A', '#N/A', '#N/A'], // [0.996747993, 970.5784629, '#N/A', '#N/A', '#N/A'],
// [459.7536742, 6, '#N/A', '#N/A', '#N/A'], // [459.7536742, 6, '#N/A', '#N/A', '#N/A'],
// [1732393319, 5652135.316, '#N/A', '#N/A', '#N/A'], // [1732393319, 5652135.316, '#N/A', '#N/A', '#N/A'],
// ],
// [142000, 144000, 151000, 150000, 139000, 169000, 126000, 142900, 163000, 169000, 149000],
// [
// [2310, 2, 2, 20],
// [2333, 2, 2, 12],
// [2356, 3, 1.5, 33],
// [2379, 3, 2, 43],
// [2402, 2, 3, 53],
// [2425, 4, 2, 23],
// [2448, 2, 1.5, 99],
// [2471, 2, 2, 34],
// [2494, 3, 3, 23],
// [2517, 4, 4, 55],
// [2540, 2, 3, 22],
// ],
// true,
// true,
// ], // ],
// [142000, 144000, 151000, 150000, 139000, 169000, 126000, 142900, 163000, 169000, 149000],
// [
// [2310, 2, 2, 20],
// [2333, 2, 2, 12],
// [2356, 3, 1.5, 33],
// [2379, 3, 2, 43],
// [2402, 2, 3, 53],
// [2425, 4, 2, 23],
// [2448, 2, 1.5, 99],
// [2471, 2, 2, 34],
// [2494, 3, 3, 23],
// [2517, 4, 4, 55],
// [2540, 2, 3, 22],
// ],
// true,
// true,
// ],
]; ];

View File

@ -1,6 +1,20 @@
<?php <?php
return [ return [
[
[1.000174230092, 1.0],
[1, 2, 3, 4, 5],
[1, 10, 100, 1000, 10000],
false,
false,
],
[
[1.000091183030, 2.127357620703],
[1, 2, 3, 4, 5],
[1, 10, 100, 1000, 10000],
true,
false,
],
[ [
[1.463275628116, 495.304770158727], [1.463275628116, 495.304770158727],
[33100, 47300, 69000, 102000, 150000, 220000], [33100, 47300, 69000, 102000, 150000, 220000],
@ -15,4 +29,44 @@ return [
true, true,
false, false,
], ],
[
[1.1743674215053, 1.0],
[3, 10, 3, 6, 8, 12, 1, 4, 9, 14],
[8, 2, 11, 6, 5, 4, 12, 9, 6, 1],
false,
false,
],
[
[0.8135120728565, 20.671878197178],
[3, 10, 3, 6, 8, 12, 1, 4, 9, 14],
[8, 2, 11, 6, 5, 4, 12, 9, 6, 1],
true,
false,
],
// [
// [
// [1.174367421505266, 1.0],
// [0.0672620306083, Functions::NA()],
// [0.3881799938732, 1.545563794251],
// [5.7102087376569, 9],
// [13.6403607201119, 21.498906978904],
// ],
// [3, 10, 3, 6, 8, 12, 1, 4, 9, 14],
// [8, 2, 11, 6, 5, 4, 12, 9, 6, 1],
// false,
// true,
// ],
// [
// [
// [0.8135120728565, 20.671878197178],
// [0.0313021171611, 0.227452478657],
// [0.8445875527654, 0.340603858743],
// [43.4759283593386, 8],
// [5.0436854288511, 0.928087908723],
// ],
// [3, 10, 3, 6, 8, 12, 1, 4, 9, 14],
// [8, 2, 11, 6, 5, 4, 12, 9, 6, 1],
// true,
// true,
// ],
]; ];

View File

@ -0,0 +1,12 @@
<?php
return [
[
'slope' => [0.8, 0.813512072856517],
'intersect' => [20.7, 20.671878197177865],
'goodnessOfFit' => [0.904868, 0.9048681877346413],
'equation' => 'Y = 20.67 * 0.81^X',
[3, 10, 3, 6, 8, 12, 1, 4, 9, 14],
[8, 2, 11, 6, 5, 4, 12, 9, 6, 1],
],
];

View File

@ -0,0 +1,20 @@
<?php
return [
[
'slope' => [-1.1, -1.1064189189190],
'intersect' => [14.1, 14.081081081081],
'goodnessOfFit' => [0.873138, 0.8731378215564962],
'equation' => 'Y = 14.08 + -1.11 * X',
[3, 10, 3, 6, 8, 12, 1, 4, 9, 14],
[8, 2, 11, 6, 5, 4, 12, 9, 6, 1],
],
[
'slope' => [1.0, 1.0],
'intersect' => [-2.0, -2.0],
'goodnessOfFit' => [1.0, 1.0],
'equation' => 'Y = -2 + 1 * X',
[1, 2, 3, 4, 5],
[3, 4, 5, 6, 7],
],
];