bestFitClass.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404
  1. <?php
  2. /**
  3. * 重庆赤晓店信息科技有限公司
  4. * https://www.chixiaodian.com
  5. * Copyright (c) 2023 赤店商城 All rights reserved.
  6. */
  7. class PHPExcel_Best_Fit
  8. {
  9. /**
  10. * Indicator flag for a calculation error
  11. *
  12. * @var boolean
  13. **/
  14. protected $error = false;
  15. /**
  16. * Algorithm type to use for best-fit
  17. *
  18. * @var string
  19. **/
  20. protected $bestFitType = 'undetermined';
  21. /**
  22. * Number of entries in the sets of x- and y-value arrays
  23. *
  24. * @var int
  25. **/
  26. protected $valueCount = 0;
  27. /**
  28. * X-value dataseries of values
  29. *
  30. * @var float[]
  31. **/
  32. protected $xValues = array();
  33. /**
  34. * Y-value dataseries of values
  35. *
  36. * @var float[]
  37. **/
  38. protected $yValues = array();
  39. /**
  40. * Flag indicating whether values should be adjusted to Y=0
  41. *
  42. * @var boolean
  43. **/
  44. protected $adjustToZero = false;
  45. /**
  46. * Y-value series of best-fit values
  47. *
  48. * @var float[]
  49. **/
  50. protected $yBestFitValues = array();
  51. protected $goodnessOfFit = 1;
  52. protected $stdevOfResiduals = 0;
  53. protected $covariance = 0;
  54. protected $correlation = 0;
  55. protected $SSRegression = 0;
  56. protected $SSResiduals = 0;
  57. protected $DFResiduals = 0;
  58. protected $f = 0;
  59. protected $slope = 0;
  60. protected $slopeSE = 0;
  61. protected $intersect = 0;
  62. protected $intersectSE = 0;
  63. protected $xOffset = 0;
  64. protected $yOffset = 0;
  65. public function getError()
  66. {
  67. return $this->error;
  68. }
  69. public function getBestFitType()
  70. {
  71. return $this->bestFitType;
  72. }
  73. /**
  74. * Return the Y-Value for a specified value of X
  75. *
  76. * @param float $xValue X-Value
  77. * @return float Y-Value
  78. */
  79. public function getValueOfYForX($xValue)
  80. {
  81. return false;
  82. }
  83. /**
  84. * Return the X-Value for a specified value of Y
  85. *
  86. * @param float $yValue Y-Value
  87. * @return float X-Value
  88. */
  89. public function getValueOfXForY($yValue)
  90. {
  91. return false;
  92. }
  93. /**
  94. * Return the original set of X-Values
  95. *
  96. * @return float[] X-Values
  97. */
  98. public function getXValues()
  99. {
  100. return $this->xValues;
  101. }
  102. /**
  103. * Return the Equation of the best-fit line
  104. *
  105. * @param int $dp Number of places of decimal precision to display
  106. * @return string
  107. */
  108. public function getEquation($dp = 0)
  109. {
  110. return false;
  111. }
  112. /**
  113. * Return the Slope of the line
  114. *
  115. * @param int $dp Number of places of decimal precision to display
  116. * @return string
  117. */
  118. public function getSlope($dp = 0)
  119. {
  120. if ($dp != 0) {
  121. return round($this->slope, $dp);
  122. }
  123. return $this->slope;
  124. }
  125. /**
  126. * Return the standard error of the Slope
  127. *
  128. * @param int $dp Number of places of decimal precision to display
  129. * @return string
  130. */
  131. public function getSlopeSE($dp = 0)
  132. {
  133. if ($dp != 0) {
  134. return round($this->slopeSE, $dp);
  135. }
  136. return $this->slopeSE;
  137. }
  138. /**
  139. * Return the Value of X where it intersects Y = 0
  140. *
  141. * @param int $dp Number of places of decimal precision to display
  142. * @return string
  143. */
  144. public function getIntersect($dp = 0)
  145. {
  146. if ($dp != 0) {
  147. return round($this->intersect, $dp);
  148. }
  149. return $this->intersect;
  150. }
  151. /**
  152. * Return the standard error of the Intersect
  153. *
  154. * @param int $dp Number of places of decimal precision to display
  155. * @return string
  156. */
  157. public function getIntersectSE($dp = 0)
  158. {
  159. if ($dp != 0) {
  160. return round($this->intersectSE, $dp);
  161. }
  162. return $this->intersectSE;
  163. }
  164. /**
  165. * Return the goodness of fit for this regression
  166. *
  167. * @param int $dp Number of places of decimal precision to return
  168. * @return float
  169. */
  170. public function getGoodnessOfFit($dp = 0)
  171. {
  172. if ($dp != 0) {
  173. return round($this->goodnessOfFit, $dp);
  174. }
  175. return $this->goodnessOfFit;
  176. }
  177. public function getGoodnessOfFitPercent($dp = 0)
  178. {
  179. if ($dp != 0) {
  180. return round($this->goodnessOfFit * 100, $dp);
  181. }
  182. return $this->goodnessOfFit * 100;
  183. }
  184. /**
  185. * Return the standard deviation of the residuals for this regression
  186. *
  187. * @param int $dp Number of places of decimal precision to return
  188. * @return float
  189. */
  190. public function getStdevOfResiduals($dp = 0)
  191. {
  192. if ($dp != 0) {
  193. return round($this->stdevOfResiduals, $dp);
  194. }
  195. return $this->stdevOfResiduals;
  196. }
  197. public function getSSRegression($dp = 0)
  198. {
  199. if ($dp != 0) {
  200. return round($this->SSRegression, $dp);
  201. }
  202. return $this->SSRegression;
  203. }
  204. public function getSSResiduals($dp = 0)
  205. {
  206. if ($dp != 0) {
  207. return round($this->SSResiduals, $dp);
  208. }
  209. return $this->SSResiduals;
  210. }
  211. public function getDFResiduals($dp = 0)
  212. {
  213. if ($dp != 0) {
  214. return round($this->DFResiduals, $dp);
  215. }
  216. return $this->DFResiduals;
  217. }
  218. public function getF($dp = 0)
  219. {
  220. if ($dp != 0) {
  221. return round($this->f, $dp);
  222. }
  223. return $this->f;
  224. }
  225. public function getCovariance($dp = 0)
  226. {
  227. if ($dp != 0) {
  228. return round($this->covariance, $dp);
  229. }
  230. return $this->covariance;
  231. }
  232. public function getCorrelation($dp = 0)
  233. {
  234. if ($dp != 0) {
  235. return round($this->correlation, $dp);
  236. }
  237. return $this->correlation;
  238. }
  239. public function getYBestFitValues()
  240. {
  241. return $this->yBestFitValues;
  242. }
  243. protected function calculateGoodnessOfFit($sumX, $sumY, $sumX2, $sumY2, $sumXY, $meanX, $meanY, $const)
  244. {
  245. $SSres = $SScov = $SScor = $SStot = $SSsex = 0.0;
  246. foreach ($this->xValues as $xKey => $xValue) {
  247. $bestFitY = $this->yBestFitValues[$xKey] = $this->getValueOfYForX($xValue);
  248. $SSres += ($this->yValues[$xKey] - $bestFitY) * ($this->yValues[$xKey] - $bestFitY);
  249. if ($const) {
  250. $SStot += ($this->yValues[$xKey] - $meanY) * ($this->yValues[$xKey] - $meanY);
  251. } else {
  252. $SStot += $this->yValues[$xKey] * $this->yValues[$xKey];
  253. }
  254. $SScov += ($this->xValues[$xKey] - $meanX) * ($this->yValues[$xKey] - $meanY);
  255. if ($const) {
  256. $SSsex += ($this->xValues[$xKey] - $meanX) * ($this->xValues[$xKey] - $meanX);
  257. } else {
  258. $SSsex += $this->xValues[$xKey] * $this->xValues[$xKey];
  259. }
  260. }
  261. $this->SSResiduals = $SSres;
  262. $this->DFResiduals = $this->valueCount - 1 - $const;
  263. if ($this->DFResiduals == 0.0) {
  264. $this->stdevOfResiduals = 0.0;
  265. } else {
  266. $this->stdevOfResiduals = sqrt($SSres / $this->DFResiduals);
  267. }
  268. if (($SStot == 0.0) || ($SSres == $SStot)) {
  269. $this->goodnessOfFit = 1;
  270. } else {
  271. $this->goodnessOfFit = 1 - ($SSres / $SStot);
  272. }
  273. $this->SSRegression = $this->goodnessOfFit * $SStot;
  274. $this->covariance = $SScov / $this->valueCount;
  275. $this->correlation = ($this->valueCount * $sumXY - $sumX * $sumY) / sqrt(($this->valueCount * $sumX2 - pow($sumX, 2)) * ($this->valueCount * $sumY2 - pow($sumY, 2)));
  276. $this->slopeSE = $this->stdevOfResiduals / sqrt($SSsex);
  277. $this->intersectSE = $this->stdevOfResiduals * sqrt(1 / ($this->valueCount - ($sumX * $sumX) / $sumX2));
  278. if ($this->SSResiduals != 0.0) {
  279. if ($this->DFResiduals == 0.0) {
  280. $this->f = 0.0;
  281. } else {
  282. $this->f = $this->SSRegression / ($this->SSResiduals / $this->DFResiduals);
  283. }
  284. } else {
  285. if ($this->DFResiduals == 0.0) {
  286. $this->f = 0.0;
  287. } else {
  288. $this->f = $this->SSRegression / $this->DFResiduals;
  289. }
  290. }
  291. }
  292. protected function leastSquareFit($yValues, $xValues, $const)
  293. {
  294. // calculate sums
  295. $x_sum = array_sum($xValues);
  296. $y_sum = array_sum($yValues);
  297. $meanX = $x_sum / $this->valueCount;
  298. $meanY = $y_sum / $this->valueCount;
  299. $mBase = $mDivisor = $xx_sum = $xy_sum = $yy_sum = 0.0;
  300. for ($i = 0; $i < $this->valueCount; ++$i) {
  301. $xy_sum += $xValues[$i] * $yValues[$i];
  302. $xx_sum += $xValues[$i] * $xValues[$i];
  303. $yy_sum += $yValues[$i] * $yValues[$i];
  304. if ($const) {
  305. $mBase += ($xValues[$i] - $meanX) * ($yValues[$i] - $meanY);
  306. $mDivisor += ($xValues[$i] - $meanX) * ($xValues[$i] - $meanX);
  307. } else {
  308. $mBase += $xValues[$i] * $yValues[$i];
  309. $mDivisor += $xValues[$i] * $xValues[$i];
  310. }
  311. }
  312. // calculate slope
  313. // $this->slope = (($this->valueCount * $xy_sum) - ($x_sum * $y_sum)) / (($this->valueCount * $xx_sum) - ($x_sum * $x_sum));
  314. $this->slope = $mBase / $mDivisor;
  315. // calculate intersect
  316. // $this->intersect = ($y_sum - ($this->slope * $x_sum)) / $this->valueCount;
  317. if ($const) {
  318. $this->intersect = $meanY - ($this->slope * $meanX);
  319. } else {
  320. $this->intersect = 0;
  321. }
  322. $this->calculateGoodnessOfFit($x_sum, $y_sum, $xx_sum, $yy_sum, $xy_sum, $meanX, $meanY, $const);
  323. }
  324. /**
  325. * Define the regression
  326. *
  327. * @param float[] $yValues The set of Y-values for this regression
  328. * @param float[] $xValues The set of X-values for this regression
  329. * @param boolean $const
  330. */
  331. public function __construct($yValues, $xValues = array(), $const = true)
  332. {
  333. // Calculate number of points
  334. $nY = count($yValues);
  335. $nX = count($xValues);
  336. // Define X Values if necessary
  337. if ($nX == 0) {
  338. $xValues = range(1, $nY);
  339. $nX = $nY;
  340. } elseif ($nY != $nX) {
  341. // Ensure both arrays of points are the same size
  342. $this->error = true;
  343. return false;
  344. }
  345. $this->valueCount = $nY;
  346. $this->xValues = $xValues;
  347. $this->yValues = $yValues;
  348. }
  349. }