1<?php 2/** 3 * PHPExcel 4 * 5 * Copyright (c) 2006 - 2014 PHPExcel 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this library; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 * 21 * @category PHPExcel 22 * @package PHPExcel_Shared_Trend 23 * @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel) 24 * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL 25 * @version ##VERSION##, ##DATE## 26 */ 27 28 29/** 30 * PHPExcel_Best_Fit 31 * 32 * @category PHPExcel 33 * @package PHPExcel_Shared_Trend 34 * @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel) 35 */ 36class PHPExcel_Best_Fit 37{ 38 /** 39 * Indicator flag for a calculation error 40 * 41 * @var boolean 42 **/ 43 protected $_error = False; 44 45 /** 46 * Algorithm type to use for best-fit 47 * 48 * @var string 49 **/ 50 protected $_bestFitType = 'undetermined'; 51 52 /** 53 * Number of entries in the sets of x- and y-value arrays 54 * 55 * @var int 56 **/ 57 protected $_valueCount = 0; 58 59 /** 60 * X-value dataseries of values 61 * 62 * @var float[] 63 **/ 64 protected $_xValues = array(); 65 66 /** 67 * Y-value dataseries of values 68 * 69 * @var float[] 70 **/ 71 protected $_yValues = array(); 72 73 /** 74 * Flag indicating whether values should be adjusted to Y=0 75 * 76 * @var boolean 77 **/ 78 protected $_adjustToZero = False; 79 80 /** 81 * Y-value series of best-fit values 82 * 83 * @var float[] 84 **/ 85 protected $_yBestFitValues = array(); 86 87 protected $_goodnessOfFit = 1; 88 89 protected $_stdevOfResiduals = 0; 90 91 protected $_covariance = 0; 92 93 protected $_correlation = 0; 94 95 protected $_SSRegression = 0; 96 97 protected $_SSResiduals = 0; 98 99 protected $_DFResiduals = 0; 100 101 protected $_F = 0; 102 103 protected $_slope = 0; 104 105 protected $_slopeSE = 0; 106 107 protected $_intersect = 0; 108 109 protected $_intersectSE = 0; 110 111 protected $_Xoffset = 0; 112 113 protected $_Yoffset = 0; 114 115 116 public function getError() { 117 return $this->_error; 118 } // function getBestFitType() 119 120 121 public function getBestFitType() { 122 return $this->_bestFitType; 123 } // function getBestFitType() 124 125 126 /** 127 * Return the Y-Value for a specified value of X 128 * 129 * @param float $xValue X-Value 130 * @return float Y-Value 131 */ 132 public function getValueOfYForX($xValue) { 133 return False; 134 } // function getValueOfYForX() 135 136 137 /** 138 * Return the X-Value for a specified value of Y 139 * 140 * @param float $yValue Y-Value 141 * @return float X-Value 142 */ 143 public function getValueOfXForY($yValue) { 144 return False; 145 } // function getValueOfXForY() 146 147 148 /** 149 * Return the original set of X-Values 150 * 151 * @return float[] X-Values 152 */ 153 public function getXValues() { 154 return $this->_xValues; 155 } // function getValueOfXForY() 156 157 158 /** 159 * Return the Equation of the best-fit line 160 * 161 * @param int $dp Number of places of decimal precision to display 162 * @return string 163 */ 164 public function getEquation($dp=0) { 165 return False; 166 } // function getEquation() 167 168 169 /** 170 * Return the Slope of the line 171 * 172 * @param int $dp Number of places of decimal precision to display 173 * @return string 174 */ 175 public function getSlope($dp=0) { 176 if ($dp != 0) { 177 return round($this->_slope,$dp); 178 } 179 return $this->_slope; 180 } // function getSlope() 181 182 183 /** 184 * Return the standard error of the Slope 185 * 186 * @param int $dp Number of places of decimal precision to display 187 * @return string 188 */ 189 public function getSlopeSE($dp=0) { 190 if ($dp != 0) { 191 return round($this->_slopeSE,$dp); 192 } 193 return $this->_slopeSE; 194 } // function getSlopeSE() 195 196 197 /** 198 * Return the Value of X where it intersects Y = 0 199 * 200 * @param int $dp Number of places of decimal precision to display 201 * @return string 202 */ 203 public function getIntersect($dp=0) { 204 if ($dp != 0) { 205 return round($this->_intersect,$dp); 206 } 207 return $this->_intersect; 208 } // function getIntersect() 209 210 211 /** 212 * Return the standard error of the Intersect 213 * 214 * @param int $dp Number of places of decimal precision to display 215 * @return string 216 */ 217 public function getIntersectSE($dp=0) { 218 if ($dp != 0) { 219 return round($this->_intersectSE,$dp); 220 } 221 return $this->_intersectSE; 222 } // function getIntersectSE() 223 224 225 /** 226 * Return the goodness of fit for this regression 227 * 228 * @param int $dp Number of places of decimal precision to return 229 * @return float 230 */ 231 public function getGoodnessOfFit($dp=0) { 232 if ($dp != 0) { 233 return round($this->_goodnessOfFit,$dp); 234 } 235 return $this->_goodnessOfFit; 236 } // function getGoodnessOfFit() 237 238 239 public function getGoodnessOfFitPercent($dp=0) { 240 if ($dp != 0) { 241 return round($this->_goodnessOfFit * 100,$dp); 242 } 243 return $this->_goodnessOfFit * 100; 244 } // function getGoodnessOfFitPercent() 245 246 247 /** 248 * Return the standard deviation of the residuals for this regression 249 * 250 * @param int $dp Number of places of decimal precision to return 251 * @return float 252 */ 253 public function getStdevOfResiduals($dp=0) { 254 if ($dp != 0) { 255 return round($this->_stdevOfResiduals,$dp); 256 } 257 return $this->_stdevOfResiduals; 258 } // function getStdevOfResiduals() 259 260 261 public function getSSRegression($dp=0) { 262 if ($dp != 0) { 263 return round($this->_SSRegression,$dp); 264 } 265 return $this->_SSRegression; 266 } // function getSSRegression() 267 268 269 public function getSSResiduals($dp=0) { 270 if ($dp != 0) { 271 return round($this->_SSResiduals,$dp); 272 } 273 return $this->_SSResiduals; 274 } // function getSSResiduals() 275 276 277 public function getDFResiduals($dp=0) { 278 if ($dp != 0) { 279 return round($this->_DFResiduals,$dp); 280 } 281 return $this->_DFResiduals; 282 } // function getDFResiduals() 283 284 285 public function getF($dp=0) { 286 if ($dp != 0) { 287 return round($this->_F,$dp); 288 } 289 return $this->_F; 290 } // function getF() 291 292 293 public function getCovariance($dp=0) { 294 if ($dp != 0) { 295 return round($this->_covariance,$dp); 296 } 297 return $this->_covariance; 298 } // function getCovariance() 299 300 301 public function getCorrelation($dp=0) { 302 if ($dp != 0) { 303 return round($this->_correlation,$dp); 304 } 305 return $this->_correlation; 306 } // function getCorrelation() 307 308 309 public function getYBestFitValues() { 310 return $this->_yBestFitValues; 311 } // function getYBestFitValues() 312 313 314 protected function _calculateGoodnessOfFit($sumX,$sumY,$sumX2,$sumY2,$sumXY,$meanX,$meanY, $const) { 315 $SSres = $SScov = $SScor = $SStot = $SSsex = 0.0; 316 foreach($this->_xValues as $xKey => $xValue) { 317 $bestFitY = $this->_yBestFitValues[$xKey] = $this->getValueOfYForX($xValue); 318 319 $SSres += ($this->_yValues[$xKey] - $bestFitY) * ($this->_yValues[$xKey] - $bestFitY); 320 if ($const) { 321 $SStot += ($this->_yValues[$xKey] - $meanY) * ($this->_yValues[$xKey] - $meanY); 322 } else { 323 $SStot += $this->_yValues[$xKey] * $this->_yValues[$xKey]; 324 } 325 $SScov += ($this->_xValues[$xKey] - $meanX) * ($this->_yValues[$xKey] - $meanY); 326 if ($const) { 327 $SSsex += ($this->_xValues[$xKey] - $meanX) * ($this->_xValues[$xKey] - $meanX); 328 } else { 329 $SSsex += $this->_xValues[$xKey] * $this->_xValues[$xKey]; 330 } 331 } 332 333 $this->_SSResiduals = $SSres; 334 $this->_DFResiduals = $this->_valueCount - 1 - $const; 335 336 if ($this->_DFResiduals == 0.0) { 337 $this->_stdevOfResiduals = 0.0; 338 } else { 339 $this->_stdevOfResiduals = sqrt($SSres / $this->_DFResiduals); 340 } 341 if (($SStot == 0.0) || ($SSres == $SStot)) { 342 $this->_goodnessOfFit = 1; 343 } else { 344 $this->_goodnessOfFit = 1 - ($SSres / $SStot); 345 } 346 347 $this->_SSRegression = $this->_goodnessOfFit * $SStot; 348 $this->_covariance = $SScov / $this->_valueCount; 349 $this->_correlation = ($this->_valueCount * $sumXY - $sumX * $sumY) / sqrt(($this->_valueCount * $sumX2 - pow($sumX,2)) * ($this->_valueCount * $sumY2 - pow($sumY,2))); 350 $this->_slopeSE = $this->_stdevOfResiduals / sqrt($SSsex); 351 $this->_intersectSE = $this->_stdevOfResiduals * sqrt(1 / ($this->_valueCount - ($sumX * $sumX) / $sumX2)); 352 if ($this->_SSResiduals != 0.0) { 353 if ($this->_DFResiduals == 0.0) { 354 $this->_F = 0.0; 355 } else { 356 $this->_F = $this->_SSRegression / ($this->_SSResiduals / $this->_DFResiduals); 357 } 358 } else { 359 if ($this->_DFResiduals == 0.0) { 360 $this->_F = 0.0; 361 } else { 362 $this->_F = $this->_SSRegression / $this->_DFResiduals; 363 } 364 } 365 } // function _calculateGoodnessOfFit() 366 367 368 protected function _leastSquareFit($yValues, $xValues, $const) { 369 // calculate sums 370 $x_sum = array_sum($xValues); 371 $y_sum = array_sum($yValues); 372 $meanX = $x_sum / $this->_valueCount; 373 $meanY = $y_sum / $this->_valueCount; 374 $mBase = $mDivisor = $xx_sum = $xy_sum = $yy_sum = 0.0; 375 for($i = 0; $i < $this->_valueCount; ++$i) { 376 $xy_sum += $xValues[$i] * $yValues[$i]; 377 $xx_sum += $xValues[$i] * $xValues[$i]; 378 $yy_sum += $yValues[$i] * $yValues[$i]; 379 380 if ($const) { 381 $mBase += ($xValues[$i] - $meanX) * ($yValues[$i] - $meanY); 382 $mDivisor += ($xValues[$i] - $meanX) * ($xValues[$i] - $meanX); 383 } else { 384 $mBase += $xValues[$i] * $yValues[$i]; 385 $mDivisor += $xValues[$i] * $xValues[$i]; 386 } 387 } 388 389 // calculate slope 390// $this->_slope = (($this->_valueCount * $xy_sum) - ($x_sum * $y_sum)) / (($this->_valueCount * $xx_sum) - ($x_sum * $x_sum)); 391 $this->_slope = $mBase / $mDivisor; 392 393 // calculate intersect 394// $this->_intersect = ($y_sum - ($this->_slope * $x_sum)) / $this->_valueCount; 395 if ($const) { 396 $this->_intersect = $meanY - ($this->_slope * $meanX); 397 } else { 398 $this->_intersect = 0; 399 } 400 401 $this->_calculateGoodnessOfFit($x_sum,$y_sum,$xx_sum,$yy_sum,$xy_sum,$meanX,$meanY,$const); 402 } // function _leastSquareFit() 403 404 405 /** 406 * Define the regression 407 * 408 * @param float[] $yValues The set of Y-values for this regression 409 * @param float[] $xValues The set of X-values for this regression 410 * @param boolean $const 411 */ 412 function __construct($yValues, $xValues=array(), $const=True) { 413 // Calculate number of points 414 $nY = count($yValues); 415 $nX = count($xValues); 416 417 // Define X Values if necessary 418 if ($nX == 0) { 419 $xValues = range(1,$nY); 420 $nX = $nY; 421 } elseif ($nY != $nX) { 422 // Ensure both arrays of points are the same size 423 $this->_error = True; 424 return False; 425 } 426 427 $this->_valueCount = $nY; 428 $this->_xValues = $xValues; 429 $this->_yValues = $yValues; 430 } // function __construct() 431 432} // class bestFit 433