Differences Between: [Versions 310 and 311] [Versions 310 and 400] [Versions 310 and 401] [Versions 310 and 402] [Versions 310 and 403]
1 <?php 2 3 namespace PhpOffice\PhpSpreadsheet\Shared\Trend; 4 5 use PhpOffice\PhpSpreadsheet\Shared\JAMA\Matrix; 6 7 class PolynomialBestFit extends BestFit 8 { 9 /** 10 * Algorithm type to use for best-fit 11 * (Name of this Trend class). 12 * 13 * @var string 14 */ 15 protected $bestFitType = 'polynomial'; 16 17 /** 18 * Polynomial order. 19 * 20 * @var int 21 */ 22 protected $order = 0; 23 24 /** 25 * Return the order of this polynomial. 26 * 27 * @return int 28 */ 29 public function getOrder() 30 { 31 return $this->order; 32 } 33 34 /** 35 * Return the Y-Value for a specified value of X. 36 * 37 * @param float $xValue X-Value 38 * 39 * @return float Y-Value 40 */ 41 public function getValueOfYForX($xValue) 42 { 43 $retVal = $this->getIntersect(); 44 $slope = $this->getSlope(); 45 foreach ($slope as $key => $value) { 46 if ($value != 0.0) { 47 $retVal += $value * pow($xValue, $key + 1); 48 } 49 } 50 51 return $retVal; 52 } 53 54 /** 55 * Return the X-Value for a specified value of Y. 56 * 57 * @param float $yValue Y-Value 58 * 59 * @return float X-Value 60 */ 61 public function getValueOfXForY($yValue) 62 { 63 return ($yValue - $this->getIntersect()) / $this->getSlope(); 64 } 65 66 /** 67 * Return the Equation of the best-fit line. 68 * 69 * @param int $dp Number of places of decimal precision to display 70 * 71 * @return string 72 */ 73 public function getEquation($dp = 0) 74 { 75 $slope = $this->getSlope($dp); 76 $intersect = $this->getIntersect($dp); 77 78 $equation = 'Y = ' . $intersect; 79 foreach ($slope as $key => $value) { 80 if ($value != 0.0) { 81 $equation .= ' + ' . $value . ' * X'; 82 if ($key > 0) { 83 $equation .= '^' . ($key + 1); 84 } 85 } 86 } 87 88 return $equation; 89 } 90 91 /** 92 * Return the Slope of the line. 93 * 94 * @param int $dp Number of places of decimal precision to display 95 * 96 * @return string 97 */ 98 public function getSlope($dp = 0) 99 { 100 if ($dp != 0) { 101 $coefficients = []; 102 foreach ($this->slope as $coefficient) { 103 $coefficients[] = round($coefficient, $dp); 104 } 105 106 return $coefficients; 107 } 108 109 return $this->slope; 110 } 111 112 public function getCoefficients($dp = 0) 113 { 114 return array_merge([$this->getIntersect($dp)], $this->getSlope($dp)); 115 } 116 117 /** 118 * Execute the regression and calculate the goodness of fit for a set of X and Y data values. 119 * 120 * @param int $order Order of Polynomial for this regression 121 * @param float[] $yValues The set of Y-values for this regression 122 * @param float[] $xValues The set of X-values for this regression 123 */ 124 private function polynomialRegression($order, $yValues, $xValues) 125 { 126 // calculate sums 127 $x_sum = array_sum($xValues); 128 $y_sum = array_sum($yValues); 129 $xx_sum = $xy_sum = $yy_sum = 0; 130 for ($i = 0; $i < $this->valueCount; ++$i) { 131 $xy_sum += $xValues[$i] * $yValues[$i]; 132 $xx_sum += $xValues[$i] * $xValues[$i]; 133 $yy_sum += $yValues[$i] * $yValues[$i]; 134 } 135 /* 136 * This routine uses logic from the PHP port of polyfit version 0.1 137 * written by Michael Bommarito and Paul Meagher 138 * 139 * The function fits a polynomial function of order $order through 140 * a series of x-y data points using least squares. 141 * 142 */ 143 $A = []; 144 $B = []; 145 for ($i = 0; $i < $this->valueCount; ++$i) { 146 for ($j = 0; $j <= $order; ++$j) { 147 $A[$i][$j] = pow($xValues[$i], $j); 148 } 149 } 150 for ($i = 0; $i < $this->valueCount; ++$i) { 151 $B[$i] = [$yValues[$i]]; 152 } 153 $matrixA = new Matrix($A); 154 $matrixB = new Matrix($B); 155 $C = $matrixA->solve($matrixB); 156 157 $coefficients = []; 158 for ($i = 0; $i < $C->getRowDimension(); ++$i) { 159 $r = $C->get($i, 0); 160 if (abs($r) <= pow(10, -9)) { 161 $r = 0; 162 } 163 $coefficients[] = $r; 164 } 165 166 $this->intersect = array_shift($coefficients); 167 $this->slope = $coefficients; 168 169 $this->calculateGoodnessOfFit($x_sum, $y_sum, $xx_sum, $yy_sum, $xy_sum, 0, 0, 0); 170 foreach ($this->xValues as $xKey => $xValue) { 171 $this->yBestFitValues[$xKey] = $this->getValueOfYForX($xValue); 172 } 173 } 174 175 /** 176 * Define the regression and calculate the goodness of fit for a set of X and Y data values. 177 * 178 * @param int $order Order of Polynomial for this regression 179 * @param float[] $yValues The set of Y-values for this regression 180 * @param float[] $xValues The set of X-values for this regression 181 * @param bool $const 182 */ 183 public function __construct($order, $yValues, $xValues = [], $const = true) 184 { 185 parent::__construct($yValues, $xValues); 186 187 if (!$this->error) { 188 if ($order < $this->valueCount) { 189 $this->bestFitType .= '_' . $order; 190 $this->order = $order; 191 $this->polynomialRegression($order, $yValues, $xValues); 192 if (($this->getGoodnessOfFit() < 0.0) || ($this->getGoodnessOfFit() > 1.0)) { 193 $this->error = true; 194 } 195 } else { 196 $this->error = true; 197 } 198 } 199 } 200 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body