File Source for Stats.php

Math_Stats

# Source for file Stats.php

Documentation is available at Stats.php

1. <?php
2. //
3. // +----------------------------------------------------------------------+
4. // | PHP Version 4 |
5. // +----------------------------------------------------------------------+
6. // | Copyright (c) 1997-2003 The PHP Group |
7. // +----------------------------------------------------------------------+
8. // | This source file is subject to version 2.0 of the PHP license, |
9. // | that is bundled with this package in the file LICENSE, and is |
10. // | available at through the world-wide-web at |
11. // | http://www.php.net/license/2_02.txt. |
12. // | If you did not receive a copy of the PHP license and are unable to |
13. // | obtain it through the world-wide-web, please send a note to |
14. // | license@php.net so we can mail you a copy immediately. |
15. // +----------------------------------------------------------------------+
16. // | Authors: Jesus M. Castagnetto <jmcastagnetto@php.net> |
17. // +----------------------------------------------------------------------+
18. //
19. // $Id: Stats.php,v 1.15 2003/06/01 11:40:30 jmcastagnetto Exp $
20. //
22. include_once 'PEAR.php';
24. /**
25. * @package Math_Stats
26. */
28. // Constants for defining the statistics to calculate /*{{{*/
29. /**
30. * STATS_BASIC to generate the basic descriptive statistics
31. */
32. define('STATS_BASIC', 1);
33. /**
34. * STATS_FULL to generate also higher moments, mode, median, etc.
35. */
36. define('STATS_FULL', 2);
37. /*}}}*/
39. // Constants describing the data set format /*{{{*/
40. /**
41. * STATS_DATA_SIMPLE for an array of numeric values. This is the default.
42. * e.g. $data = array(2,3,4,5,1,1,6);
43. */
44. define('STATS_DATA_SIMPLE', 0);
45. /**
46. * STATS_DATA_CUMMULATIVE for an associative array of frequency values,
47. * where in each array entry, the index is the data point and the
48. * value the count (frequency):
49. * e.g. $data = array(3=>4, 2.3=>5, 1.25=>6, 0.5=>3)
50. */
51. define('STATS_DATA_CUMMULATIVE', 1);
52. /*}}}*/
54. // Constants defining how to handle nulls /*{{{*/
55. /**
56. * STATS_REJECT_NULL, reject data sets with null values. This is the default.
57. * Any non-numeric value is considered a null in this context.
58. */
59. define('STATS_REJECT_NULL', -1);
60. /**
61. * STATS_IGNORE_NULL, ignore null values and prune them from the data.
62. * Any non-numeric value is considered a null in this context.
63. */
64. define('STATS_IGNORE_NULL', -2);
65. /**
66. * STATS_USE_NULL_AS_ZERO, assign the value of 0 (zero) to null values.
67. * Any non-numeric value is considered a null in this context.
68. */
69. define('STATS_USE_NULL_AS_ZERO', -3);
70. /*}}}*/
72. /**
73. * A class to calculate descriptive statistics from a data set.
74. * Data sets can be simple arrays of data, or a cummulative hash.
75. * The second form is useful when passing large data set,
76. * for example the data set:
77. *
78. * <pre>
79. * $data1 = array (1,2,1,1,1,1,3,3,4.1,3,2,2,4.1,1,1,2,3,3,2,2,1,1,2,2);
80. * </pre>
81. *
82. * can be epxressed more compactly as:
83. *
84. * <pre>
85. * $data2 = array('1'=>9, '2'=>8, '3'=>5, '4.1'=>2);
86. * </pre>
87. *
88. * Example of use:
89. *
90. * <pre>
91. * include_once 'Math/Stats.php';
92. * $s = new Math_Stats();
93. * $s->setData($data1);
94. * // or
95. * // $s->setData($data2, STATS_DATA_CUMMULATIVE);
96. * $stats = $s->calcBasic();
97. * echo 'Mean: '.$stats['mean'].' StDev: '.$stats['stdev'].' <br />\n';
98. *
99. * // using data with nulls
100. * // first ignoring them:
101. * $data3 = array(1.2, 'foo', 2.4, 3.1, 4.2, 3.2, null, 5.1, 6.2);
102. * $s->setNullOption(STATS_IGNORE_NULL);
103. * $s->setData($data3);
104. * $stats3 = $s->calcFull();
105. *
106. * // and then assuming nulls == 0
107. * $s->setNullOption(STATS_USE_NULL_AS_ZERO);
108. * $s->setData($data3);
109. * $stats3 = $s->calcFull();
110. * </pre>
111. *
112. * Originally this class was part of NumPHP (Numeric PHP package)
113. *
114. * @author Jesus M. Castagnetto <jmcastagnetto@php.net>
115. * @version 0.8
116. * @access public
117. * @package Math_Stats
118. */
119. class Base {/*{{{*/
120. // properties /*{{{*/
122. /**
123. * The simple or cummulative data set.
124. * Null by default.
125. *
126. * @access private
127. * @var array
128. */
129. public $_data = null;
131. /**
132. * Expanded data set. Only set when cummulative data
133. * is being used. Null by default.
134. *
135. * @access private
136. * @var array
137. */
138. public $_dataExpanded = null;
140. /**
141. * Flag for data type, one of STATS_DATA_SIMPLE or
142. * STATS_DATA_CUMMULATIVE. Null by default.
143. *
144. * @access private
145. * @var int
146. */
147. public $_dataOption = null;
149. /**
150. * Flag for null handling options. One of STATS_REJECT_NULL,
151. * STATS_IGNORE_NULL or STATS_USE_NULL_AS_ZERO
152. *
153. * @access private
154. * @var int
155. */
156. public $_nullOption;
158. /**
159. * Array for caching result values, should be reset
160. * when using setData()
161. *
162. * @access private
163. * @var array
164. */
165. public $_calculatedValues = array();
167. /*}}}*/
169. /**
170. * Constructor for the class
171. *
172. * @access public
173. * @param optional int $nullOption how to handle null values
174. * @return object Math_Stats
175. */
176. function Math_Stats($nullOption=STATS_REJECT_NULL) {/*{{{*/
177. $this->_nullOption = $nullOption;
178. }/*}}}*/
180. /**
181. * Sets and verifies the data, checking for nulls and using
182. * the current null handling option
183. *
184. * @access public
185. * @param array $arr the data set
186. * @param optional int $opt data format: STATS_DATA_CUMMULATIVE or STATS_DATA_SIMPLE (default)
187. * @return mixed true on success, a PEAR_Error object otherwise
188. */
189. function setData($arr, $opt=STATS_DATA_SIMPLE) {/*{{{*/
190. if (! is_array($arr)) {
191. return PEAR:: raiseError('invalid data, an array of numeric data was expected');
192. }
193. $this->_data = null;
194. $this->_dataExpanded = null;
195. $this->_dataOption = null;
196. $this->_calculatedValues = array();
197. if ($opt == STATS_DATA_SIMPLE) {
198. $this->_dataOption = $opt;
199. $this->_data = array_values($arr);
200. } else if ($opt == STATS_DATA_CUMMULATIVE) {
201. $this->_dataOption = $opt;
202. $this->_data = $arr;
203. $this->_dataExpanded = array();
204. }
205. return $this->_validate();
206. }/*}}}*/
208. /**
209. * Returns the data which might have been modified
210. * according to the current null handling options.
211. *
212. * @access public
213. * @param boolean $expanded whether to return a expanded list, default is false
214. * @return mixed array of data on success, a PEAR_Error object otherwise
215. * @see _validate()
216. */
217. function getData($expanded=false) {/*{{{*/
218. if ($this->_data == null) {
219. return PEAR:: raiseError('data has not been set');
220. }
221. if ($this->_dataOption == STATS_DATA_CUMMULATIVE && $expanded) {
222. return $this->_dataExpanded;
223. } else {
224. return $this->_data;
225. }
226. }/*}}}*/
228. /**
229. * Sets the null handling option.
230. * Must be called before assigning a new data set containing null values
231. *
232. * @access public
233. * @return mixed true on success, a PEAR_Error object otherwise
234. * @see _validate()
235. */
236. function setNullOption($nullOption) {/*{{{*/
237. if ($nullOption == STATS_REJECT_NULL
238. || $nullOption == STATS_IGNORE_NULL
239. || $nullOption == STATS_USE_NULL_AS_ZERO) {
240. $this->_nullOption = $nullOption;
241. return true;
242. } else {
243. return PEAR:: raiseError('invalid null handling option expecting: '.
244. 'STATS_REJECT_NULL, STATS_IGNORE_NULL or STATS_USE_NULL_AS_ZERO');
245. }
246. }/*}}}*/
248. /**
249. * Transforms the data by substracting each entry from the mean and
250. * dividing by its standard deviation. This will reset all pre-calculated
251. * values to their original (unset) defaults.
252. *
253. * @access public
254. * @return mixed true on success, a PEAR_Error object otherwise
255. * @see mean()
256. * @see stDev()
257. * @see setData()
258. */
259. function studentize() {/*{{{*/
260. $mean = $this-> mean();
261. if (PEAR:: isError($mean)) {
262. return $mean;
263. }
264. $std = $this-> stDev();
265. if (PEAR:: isError($std)) {
266. return $std;
267. }
268. if ($std == 0) {
269. return PEAR:: raiseError('cannot studentize data, standard deviation is zero.');
270. }
271. $arr = array();
272. if ($this->_dataOption == STATS_DATA_CUMMULATIVE) {
273. foreach ($this->_data as $val=>$freq) {
274. $newval = ($val - $mean) / $std;
275. $arr["$newval"] = $freq;
276. }
277. } else {
278. foreach ($this->_data as $val) {
279. $newval = ($val - $mean) / $std;
280. $arr[] = $newval;
281. }
282. }
283. return $this-> setData($arr, $this->_dataOption);
284. }/*}}}*/
286. /**
287. * Transforms the data by substracting each entry from the mean.
288. * This will reset all pre-calculated values to their original (unset) defaults.
289. *
290. * @access public
291. * @return mixed true on success, a PEAR_Error object otherwise
292. * @see mean()
293. * @see setData()
294. */
295. function center() {/*{{{*/
296. $mean = $this-> mean();
297. if (PEAR:: isError($mean)) {
298. return $mean;
299. }
300. $arr = array();
301. if ($this->_dataOption == STATS_DATA_CUMMULATIVE) {
302. foreach ($this->_data as $val=>$freq) {
303. $newval = $val - $mean;
304. $arr["$newval"] = $freq;
305. }
306. } else {
307. foreach ($this->_data as $val) {
308. $newval = $val - $mean;
309. $arr[] = $newval;
310. }
311. }
312. return $this-> setData($arr, $this->_dataOption);
313. }/*}}}*/
315. /**
316. * Calculates the basic or full statistics for the data set
317. *
318. * @access public
319. * @param int $mode one of STATS_BASIC or STATS_FULL
320. * @param boolean $returnErrorObject whether the raw PEAR_Error (when true, default),
321. * or only the error message will be returned (when false), if an error happens.
322. * @return mixed an associative array of statistics on success, a PEAR_Error object otherwise
323. * @see calcBasic()
324. * @see calcFull()
325. */
326. function calc($mode, $returnErrorObject=true) {/*{{{*/
327. if ($this->_data == null) {
328. return PEAR:: raiseError('data has not been set');
329. }
330. if ($mode == STATS_BASIC) {
331. return $this-> calcBasic($returnErrorObject);
332. } elseif ($mode == STATS_FULL) {
333. return $this-> calcFull($returnErrorObject);
334. } else {
335. return PEAR:: raiseError('incorrect mode, expected STATS_BASIC or STATS_FULL');
336. }
337. }/*}}}*/
339. /**
340. * Calculates a basic set of statistics
341. *
342. * @access public
343. * @param boolean $returnErrorObject whether the raw PEAR_Error (when true, default),
344. * or only the error message will be returned (when false), if an error happens.
345. * @return mixed an associative array of statistics on success, a PEAR_Error object otherwise
346. * @see calc()
347. * @see calcFull()
348. */
349. function calcBasic($returnErrorObject=true) {/*{{{*/
350. return array (
351. 'min' => $this->__format($this-> min(), $returnErrorObject),
352. 'max' => $this->__format($this-> max(), $returnErrorObject),
353. 'sum' => $this->__format($this-> sum(), $returnErrorObject),
354. 'sum2' => $this->__format($this-> sum2(), $returnErrorObject),
355. 'count' => $this->__format($this-> count(), $returnErrorObject),
356. 'mean' => $this->__format($this-> mean(), $returnErrorObject),
357. 'stdev' => $this->__format($this-> stDev(), $returnErrorObject),
358. 'variance' => $this->__format($this-> variance(), $returnErrorObject),
359. 'range' => $this->__format($this-> range(), $returnErrorObject)
360. );
361. }/*}}}*/
363. /**
364. * Calculates a full set of statistics
365. *
366. * @access public
367. * @param boolean $returnErrorObject whether the raw PEAR_Error (when true, default),
368. * or only the error message will be returned (when false), if an error happens.
369. * @return mixed an associative array of statistics on success, a PEAR_Error object otherwise
370. * @see calc()
371. * @see calcBasic()
372. */
373. function calcFull($returnErrorObject=true) {/*{{{*/
374. return array (
375. 'min' => $this->__format($this-> min(), $returnErrorObject),
376. 'max' => $this->__format($this-> max(), $returnErrorObject),
377. 'sum' => $this->__format($this-> sum(), $returnErrorObject),
378. 'sum2' => $this->__format($this-> sum2(), $returnErrorObject),
379. 'count' => $this->__format($this-> count(), $returnErrorObject),
380. 'mean' => $this->__format($this-> mean(), $returnErrorObject),
381. 'median' => $this->__format($this-> median(), $returnErrorObject),
382. 'mode' => $this->__format($this-> mode(), $returnErrorObject),
383. 'midrange' => $this->__format($this-> midrange(), $returnErrorObject),
384. 'geometric_mean' => $this->__format($this-> geometricMean(), $returnErrorObject),
385. 'harmonic_mean' => $this->__format($this-> harmonicMean(), $returnErrorObject),
386. 'stdev' => $this->__format($this-> stDev(), $returnErrorObject),
387. 'absdev' => $this->__format($this-> absDev(), $returnErrorObject),
388. 'variance' => $this->__format($this-> variance(), $returnErrorObject),
389. 'range' => $this->__format($this-> range(), $returnErrorObject),
390. 'std_error_of_mean' => $this->__format($this-> stdErrorOfMean(), $returnErrorObject),
391. 'skewness' => $this->__format($this-> skewness(), $returnErrorObject),
392. 'kurtosis' => $this->__format($this-> kurtosis(), $returnErrorObject),
393. 'coeff_of_variation' => $this->__format($this-> coeffOfVariation(), $returnErrorObject),
394. 'sample_central_moments' => array (
395. 1 => $this->__format($this-> sampleCentralMoment(1), $returnErrorObject),
396. 2 => $this->__format($this-> sampleCentralMoment(2), $returnErrorObject),
397. 3 => $this->__format($this-> sampleCentralMoment(3), $returnErrorObject),
398. 4 => $this->__format($this-> sampleCentralMoment(4), $returnErrorObject),
399. 5 => $this->__format($this-> sampleCentralMoment(5), $returnErrorObject)
400. ),
401. 'sample_raw_moments' => array (
402. 1 => $this->__format($this-> sampleRawMoment(1), $returnErrorObject),
403. 2 => $this->__format($this-> sampleRawMoment(2), $returnErrorObject),
404. 3 => $this->__format($this-> sampleRawMoment(3), $returnErrorObject),
405. 4 => $this->__format($this-> sampleRawMoment(4), $returnErrorObject),
406. 5 => $this->__format($this-> sampleRawMoment(5), $returnErrorObject)
407. ),
408. 'frequency' => $this->__format($this-> frequency(), $returnErrorObject),
409. 'quartiles' => $this->__format($this-> quartiles(), $returnErrorObject),
410. 'interquartile_range' => $this->__format($this-> interquartileRange(), $returnErrorObject),
411. 'interquartile_mean' => $this->__format($this-> interquartileMean(), $returnErrorObject),
412. 'quartile_deviation' => $this->__format($this-> quartileDeviation(), $returnErrorObject),
413. 'quartile_variation_coefficient' => $this->__format($this-> quartileVariationCoefficient(), $returnErrorObject),
414. 'quartile_skewness_coefficient' => $this->__format($this-> quartileSkewnessCoefficient(), $returnErrorObject)
415. );
416. }/*}}}*/
418. /**
419. * Calculates the minimum of a data set.
420. * Handles cummulative data sets correctly
421. *
422. * @access public
423. * @return mixed the minimum value on success, a PEAR_Error object otherwise
424. * @see calc()
425. * @see max()
426. */
427. function min() {/*{{{*/
428. if ($this->_data == null) {
429. return PEAR:: raiseError('data has not been set');
430. }
431. if (! array_key_exists('min', $this->_calculatedValues)) {
432. if ($this->_dataOption == STATS_DATA_CUMMULATIVE) {
433. $min = min( array_keys($this->_data));
434. } else {
435. $min = min($this->_data);
436. }
437. $this->_calculatedValues['min'] = $min;
438. }
439. return $this->_calculatedValues['min'];
440. }/*}}}*/
442. /**
443. * Calculates the maximum of a data set.
444. * Handles cummulative data sets correctly
445. *
446. * @access public
447. * @return mixed the maximum value on success, a PEAR_Error object otherwise
448. * @see calc()
449. * @see min()
450. */
451. function max() {/*{{{*/
452. if ($this->_data == null) {
453. return PEAR:: raiseError('data has not been set');
454. }
455. if (! array_key_exists('max', $this->_calculatedValues)) {
456. if ($this->_dataOption == STATS_DATA_CUMMULATIVE) {
457. $max = max( array_keys($this->_data));
458. } else {
459. $max = max($this->_data);
460. }
461. $this->_calculatedValues['max'] = $max;
462. }
463. return $this->_calculatedValues['max'];
464. }/*}}}*/
466. /**
467. * Calculates SUM { xi }
468. * Handles cummulative data sets correctly
469. *
470. * @access public
471. * @return mixed the sum on success, a PEAR_Error object otherwise
472. * @see calc()
473. * @see sum2()
474. * @see sumN()
475. */
476. function sum() {/*{{{*/
477. if (! array_key_exists('sum', $this->_calculatedValues)) {
478. $sum = $this-> sumN(1);
479. if (PEAR:: isError($sum)) {
480. return $sum;
481. } else {
482. $this->_calculatedValues['sum'] = $sum;
483. }
484. }
485. return $this->_calculatedValues['sum'];
486. }/*}}}*/
488. /**
489. * Calculates SUM { (xi)^2 }
490. * Handles cummulative data sets correctly
491. *
492. * @access public
493. * @return mixed the sum on success, a PEAR_Error object otherwise
494. * @see calc()
495. * @see sum()
496. * @see sumN()
497. */
498. function sum2() {/*{{{*/
499. if (! array_key_exists('sum2', $this->_calculatedValues)) {
500. $sum2 = $this-> sumN(2);
501. if (PEAR:: isError($sum2)) {
502. return $sum2;
503. } else {
504. $this->_calculatedValues['sum2'] = $sum2;
505. }
506. }
507. return $this->_calculatedValues['sum2'];
508. }/*}}}*/
510. /**
511. * Calculates SUM { (xi)^n }
512. * Handles cummulative data sets correctly
513. *
514. * @access public
515. * @param numeric $n the exponent
516. * @return mixed the sum on success, a PEAR_Error object otherwise
517. * @see calc()
518. * @see sum()
519. * @see sum2()
520. */
521. function sumN($n) {/*{{{*/
522. if ($this->_data == null) {
523. return PEAR:: raiseError('data has not been set');
524. }
525. $sumN = 0;
526. if ($this->_dataOption == STATS_DATA_CUMMULATIVE) {
527. foreach($this->_data as $val=>$freq) {
528. $sumN += $freq * pow((double)$val, (double)$n);
529. }
530. } else {
531. foreach($this->_data as $val) {
532. $sumN += pow((double)$val, (double)$n);
533. }
534. }
535. return $sumN;
536. }/*}}}*/
538. /**
539. * Calculates PROD { (xi) }, (the product of all observations)
540. * Handles cummulative data sets correctly
541. *
542. * @access public
543. * @return mixed the product on success, a PEAR_Error object otherwise
544. * @see productN()
545. */
546. function product() {/*{{{*/
547. if (! array_key_exists('product', $this->_calculatedValues)) {
548. $product = $this-> productN(1);
549. if (PEAR:: isError($product)) {
550. return $product;
551. } else {
552. $this->_calculatedValues['product'] = $product;
553. }
554. }
555. return $this->_calculatedValues['product'];
556. }/*}}}*/
558. /**
559. * Calculates PROD { (xi)^n }, which is the product of all observations
560. * Handles cummulative data sets correctly
561. *
562. * @access public
563. * @param numeric $n the exponent
564. * @return mixed the product on success, a PEAR_Error object otherwise
565. * @see product()
566. */
567. function productN($n) {/*{{{*/
568. if ($this->_data == null) {
569. return PEAR:: raiseError('data has not been set');
570. }
571. $prodN = 1.0;
572. if ($this->_dataOption == STATS_DATA_CUMMULATIVE) {
573. foreach($this->_data as $val=>$freq) {
574. if ($val == 0) {
575. return 0.0;
576. }
577. $prodN *= $freq * pow((double)$val, (double)$n);
578. }
579. } else {
580. foreach($this->_data as $val) {
581. if ($val == 0) {
582. return 0.0;
583. }
584. $prodN *= pow((double)$val, (double)$n);
585. }
586. }
587. return $prodN;
589. }/*}}}*/
591. /**
592. * Calculates the number of data points in the set
593. * Handles cummulative data sets correctly
594. *
595. * @access public
596. * @return mixed the count on success, a PEAR_Error object otherwise
597. * @see calc()
598. */
599. function count() {/*{{{*/
600. if ($this->_data == null) {
601. return PEAR:: raiseError('data has not been set');
602. }
603. if (! array_key_exists('count', $this->_calculatedValues)) {
604. if ($this->_dataOption == STATS_DATA_CUMMULATIVE) {
605. $count = count($this->_dataExpanded);
606. } else {
607. $count = count($this->_data);
608. }
609. $this->_calculatedValues['count'] = $count;
610. }
611. return $this->_calculatedValues['count'];
612. }/*}}}*/
614. /**
615. * Calculates the mean (average) of the data points in the set
616. * Handles cummulative data sets correctly
617. *
618. * @access public
619. * @return mixed the mean value on success, a PEAR_Error object otherwise
620. * @see calc()
621. * @see sum()
622. * @see count()
623. */
624. function mean() {/*{{{*/
625. if (! array_key_exists('mean', $this->_calculatedValues)) {
626. $sum = $this-> sum();
627. if (PEAR:: isError($sum)) {
628. return $sum;
629. }
630. $count = $this-> count();
631. if (PEAR:: isError($count)) {
632. return $count;
633. }
634. $this->_calculatedValues['mean'] = $sum / $count;
635. }
636. return $this->_calculatedValues['mean'];
637. }/*}}}*/
639. /**
640. * Calculates the range of the data set = max - min
641. *
642. * @access public
643. * @return mixed the value of the range on success, a PEAR_Error object otherwise.
644. */
645. function range() {/*{{{*/
646. if (! array_key_exists('range', $this->_calculatedValues)) {
647. $min = $this-> min();
648. if (PEAR:: isError($min)) {
649. return $min;
650. }
651. $max = $this-> max();
652. if (PEAR:: isError($max)) {
653. return $max;
654. }
655. $this->_calculatedValues['range'] = $max - $min;
656. }
657. return $this->_calculatedValues['range'];
659. }/*}}}*/
661. /**
662. * Calculates the variance (unbiased) of the data points in the set
663. * Handles cummulative data sets correctly
664. *
665. * @access public
666. * @return mixed the variance value on success, a PEAR_Error object otherwise
667. * @see calc()
668. * @see __sumdiff()
669. * @see count()
670. */
671. function variance() {/*{{{*/
672. if (! array_key_exists('variance', $this->_calculatedValues)) {
673. $variance = $this->__calcVariance();
674. if (PEAR:: isError($variance)) {
675. return $variance;
676. }
677. $this->_calculatedValues['variance'] = $variance;
678. }
679. return $this->_calculatedValues['variance'];
680. }/*}}}*/
682. /**
683. * Calculates the standard deviation (unbiased) of the data points in the set
684. * Handles cummulative data sets correctly
685. *
686. * @access public
687. * @return mixed the standard deviation on success, a PEAR_Error object otherwise
688. * @see calc()
689. * @see variance()
690. */
691. function stDev() {/*{{{*/
692. if (! array_key_exists('stDev', $this->_calculatedValues)) {
693. $variance = $this-> variance();
694. if (PEAR:: isError($variance)) {
695. return $variance;
696. }
697. $this->_calculatedValues['stDev'] = sqrt($variance);
698. }
699. return $this->_calculatedValues['stDev'];
700. }/*}}}*/
702. /**
703. * Calculates the variance (unbiased) of the data points in the set
704. * given a fixed mean (average) value. Not used in calcBasic(), calcFull()
705. * or calc().
706. * Handles cummulative data sets correctly
707. *
708. * @access public
709. * @param numeric $mean the fixed mean value
710. * @return mixed the variance on success, a PEAR_Error object otherwise
711. * @see __sumdiff()
712. * @see count()
713. * @see variance()
714. */
715. function varianceWithMean($mean) {/*{{{*/
716. return $this->__calcVariance($mean);
717. }/*}}}*/
719. /**
720. * Calculates the standard deviation (unbiased) of the data points in the set
721. * given a fixed mean (average) value. Not used in calcBasic(), calcFull()
722. * or calc().
723. * Handles cummulative data sets correctly
724. *
725. * @access public
726. * @param numeric $mean the fixed mean value
727. * @return mixed the standard deviation on success, a PEAR_Error object otherwise
728. * @see varianceWithMean()
729. * @see stDev()
730. */
731. function stDevWithMean($mean) {/*{{{*/
732. $varianceWM = $this-> varianceWithMean($mean);
733. if (PEAR:: isError($varianceWM)) {
734. return $varianceWM;
735. }
736. return sqrt($varianceWM);
737. }/*}}}*/
739. /**
740. * Calculates the absolute deviation of the data points in the set
741. * Handles cummulative data sets correctly
742. *
743. * @access public
744. * @return mixed the absolute deviation on success, a PEAR_Error object otherwise
745. * @see calc()
746. * @see __sumabsdev()
747. * @see count()
748. * @see absDevWithMean()
749. */
750. function absDev() {/*{{{*/
751. if (! array_key_exists('absDev', $this->_calculatedValues)) {
752. $absDev = $this->__calcAbsoluteDeviation();
753. if (PEAR:: isError($absdev)) {
754. return $absdev;
755. }
756. $this->_calculatedValues['absDev'] = $absDev;
757. }
758. return $this->_calculatedValues['absDev'];
759. }/*}}}*/
761. /**
762. * Calculates the absolute deviation of the data points in the set
763. * given a fixed mean (average) value. Not used in calcBasic(), calcFull()
764. * or calc().
765. * Handles cummulative data sets correctly
766. *
767. * @access public
768. * @param numeric $mean the fixed mean value
769. * @return mixed the absolute deviation on success, a PEAR_Error object otherwise
770. * @see __sumabsdev()
771. * @see absDev()
772. */
773. function absDevWithMean($mean) {/*{{{*/
774. return $this->__calcAbsoluteDeviation($mean);
775. }/*}}}*/
777. /**
778. * Calculates the skewness of the data distribution in the set
779. * The skewness measures the degree of asymmetry of a distribution,
780. * and is related to the third central moment of a distribution.
781. * A normal distribution has a skewness = 0
782. * A distribution with a tail off towards the high end of the scale
783. * (positive skew) has a skewness > 0
784. * A distribution with a tail off towards the low end of the scale
785. * (negative skew) has a skewness < 0
786. * Handles cummulative data sets correctly
787. *
788. * @access public
789. * @return mixed the skewness value on success, a PEAR_Error object otherwise
790. * @see __sumdiff()
791. * @see count()
792. * @see stDev()
793. * @see calc()
794. */
795. function skewness() {/*{{{*/
796. if (! array_key_exists('skewness', $this->_calculatedValues)) {
797. $count = $this-> count();
798. if (PEAR:: isError($count)) {
799. return $count;
800. }
801. $stDev = $this-> stDev();
802. if (PEAR:: isError($stDev)) {
803. return $stDev;
804. }
805. $sumdiff3 = $this->__sumdiff(3);
806. if (PEAR:: isError($sumdiff3)) {
807. return $sumdiff3;
808. }
809. $this->_calculatedValues['skewness'] = ($sumdiff3 / ($count * pow($stDev, 3)));
810. }
811. return $this->_calculatedValues['skewness'];
812. }/*}}}*/
814. /**
815. * Calculates the kurtosis of the data distribution in the set
816. * The kurtosis measures the degrees of peakedness of a distribution.
817. * It is also called the "excess" or "excess coefficient", and is
818. * a normalized form of the fourth central moment of a distribution.
819. * A normal distributions has kurtosis = 0
820. * A narrow and peaked (leptokurtic) distribution has a
821. * kurtosis > 0
822. * A flat and wide (platykurtic) distribution has a kurtosis < 0
823. * Handles cummulative data sets correctly
824. *
825. * @access public
826. * @return mixed the kurtosis value on success, a PEAR_Error object otherwise
827. * @see __sumdiff()
828. * @see count()
829. * @see stDev()
830. * @see calc()
831. */
832. function kurtosis() {/*{{{*/
833. if (! array_key_exists('kurtosis', $this->_calculatedValues)) {
834. $count = $this-> count();
835. if (PEAR:: isError($count)) {
836. return $count;
837. }
838. $stDev = $this-> stDev();
839. if (PEAR:: isError($stDev)) {
840. return $stDev;
841. }
842. $sumdiff4 = $this->__sumdiff(4);
843. if (PEAR:: isError($sumdiff4)) {
844. return $sumdiff4;
845. }
846. $this->_calculatedValues['kurtosis'] = ($sumdiff4 / ($count * pow($stDev, 4))) - 3;
847. }
848. return $this->_calculatedValues['kurtosis'];
849. }/*}}}*/
851. /**
852. * Calculates the median of a data set.
853. * The median is the value such that half of the points are below it
854. * in a sorted data set.
855. * If the number of values is odd, it is the middle item.
856. * If the number of values is even, is the average of the two middle items.
857. * Handles cummulative data sets correctly
858. *
859. * @access public
860. * @return mixed the median value on success, a PEAR_Error object otherwise
861. * @see count()
862. * @see calc()
863. */
864. function median() {/*{{{*/
865. if ($this->_data == null) {
866. return PEAR:: raiseError('data has not been set');
867. }
868. if (! array_key_exists('median', $this->_calculatedValues)) {
869. if ($this->_dataOption == STATS_DATA_CUMMULATIVE) {
870. $arr =& $this->_dataExpanded;
871. } else {
872. $arr =& $this->_data;
873. }
874. $n = $this-> count();
875. if (PEAR:: isError($n)) {
876. return $n;
877. }
878. $h = intval($n / 2);
879. if ($n % 2 == 0) {
880. $median = ($arr[$h] + $arr[$h - 1]) / 2;
881. } else {
882. $median = $arr[$h + 1];
883. }
884. $this->_calculatedValues['median'] = $median;
885. }
886. return $this->_calculatedValues['median'];
887. }/*}}}*/
889. /**
890. * Calculates the mode of a data set.
891. * The mode is the value with the highest frequency in the data set.
892. * There can be more than one mode.
893. * Handles cummulative data sets correctly
894. *
895. * @access public
896. * @return mixed an array of mode value on success, a PEAR_Error object otherwise
897. * @see frequency()
898. * @see calc()
899. */
900. function mode() {/*{{{*/
901. if ($this->_data == null) {
902. return PEAR:: raiseError('data has not been set');
903. }
904. if (! array_key_exists('mode', $this->_calculatedValues)) {
905. if ($this->_dataOption == STATS_DATA_CUMMULATIVE) {
906. $arr = $this->_data;
907. } else {
908. $arr = $this-> frequency();
909. }
910. arsort($arr);
911. $mcount = 1;
912. foreach ($arr as $val=>$freq) {
913. if ($mcount == 1) {
914. $mode = array($val);
915. $mfreq = $freq;
916. ++$mcount;
917. continue;
918. }
919. if ($mfreq == $freq)
920. $mode[] = $val;
921. if ($mfreq > $freq)
922. break;
923. }
924. $this->_calculatedValues['mode'] = $mode;
925. }
926. return $this->_calculatedValues['mode'];
927. }/*}}}*/
929. /**
930. * Calculates the midrange of a data set.
931. * The midrange is the average of the minimum and maximum of the data set.
932. * Handles cummulative data sets correctly
933. *
934. * @access public
935. * @return mixed the midrange value on success, a PEAR_Error object otherwise
936. * @see min()
937. * @see max()
938. * @see calc()
939. */
940. function midrange() {/*{{{*/
941. if (! array_key_exists('midrange', $this->_calculatedValues)) {
942. $min = $this-> min();
943. if (PEAR:: isError($min)) {
944. return $min;
945. }
946. $max = $this-> max();
947. if (PEAR:: isError($max)) {
948. return $max;
949. }
950. $this->_calculatedValues['midrange'] = (($max + $min) / 2);
951. }
952. return $this->_calculatedValues['midrange'];
953. }/*}}}*/
955. /**
956. * Calculates the geometrical mean of the data points in the set
957. * Handles cummulative data sets correctly
958. *
959. * @access public
960. * @return mixed the geometrical mean value on success, a PEAR_Error object otherwise
961. * @see calc()
962. * @see product()
963. * @see count()
964. */
965. function geometricMean() {/*{{{*/
966. if (! array_key_exists('geometricMean', $this->_calculatedValues)) {
967. $count = $this-> count();
968. if (PEAR:: isError($count)) {
969. return $count;
970. }
971. $prod = $this-> product();
972. if (PEAR:: isError($prod)) {
973. return $prod;
974. }
975. if ($prod == 0.0) {
976. return 0.0;
977. }
978. if ($prod < 0) {
979. return PEAR:: raiseError('The product of the data set is negative, geometric mean undefined.');
980. }
981. $this->_calculatedValues['geometricMean'] = pow($prod , 1 / $count);
982. }
983. return $this->_calculatedValues['geometricMean'];
984. }/*}}}*/
986. /**
987. * Calculates the harmonic mean of the data points in the set
988. * Handles cummulative data sets correctly
989. *
990. * @access public
991. * @return mixed the harmonic mean value on success, a PEAR_Error object otherwise
992. * @see calc()
993. * @see count()
994. */
995. function harmonicMean() {/*{{{*/
996. if ($this->_data == null) {
997. return PEAR:: raiseError('data has not been set');
998. }
999. if (! array_key_exists('harmonicMean', $this->_calculatedValues)) {
1000. $count = $this-> count();
1001. if (PEAR:: isError($count)) {
1002. return $count;
1003. }
1004. $invsum = 0.0;
1005. if ($this->_dataOption == STATS_DATA_CUMMULATIVE) {
1006. foreach($this->_data as $val=>$freq) {
1007. if ($val == 0) {
1008. return PEAR:: raiseError('cannot calculate a '.
1009. 'harmonic mean with data values of zero.');
1010. }
1011. $invsum += $freq / $val;
1012. }
1013. } else {
1014. foreach($this->_data as $val) {
1015. if ($val == 0) {
1016. return PEAR:: raiseError('cannot calculate a '.
1017. 'harmonic mean with data values of zero.');
1018. }
1019. $invsum += 1 / $val;
1020. }
1021. }
1022. $this->_calculatedValues['harmonicMean'] = $count / $invsum;
1023. }
1024. return $this->_calculatedValues['harmonicMean'];
1025. }/*}}}*/
1027. /**
1028. * Calculates the nth central moment (m{n}) of a data set.
1029. *
1030. * The definition of a sample central moment is:
1031. *
1032. * m{n} = 1/N * SUM { (xi - avg)^n }
1033. *
1034. * where: N = sample size, avg = sample mean.
1035. *
1036. * @access public
1037. * @param integer $n moment to calculate
1038. * @return mixed the numeric value of the moment on success, PEAR_Error otherwise
1039. */
1040. function sampleCentralMoment($n) {/*{{{*/
1041. if (! is_int($n) || $n < 1) {
1042. return PEAR:: isError('moment must be a positive integer >= 1.');
1043. }
1045. if ($n == 1) {
1046. return 0;
1047. }
1048. $count = $this-> count();
1049. if (PEAR:: isError($count)) {
1050. return $count;
1051. }
1052. if ($count == 0) {
1053. return PEAR:: raiseError("Cannot calculate {$n}th sample moment, ".
1054. 'there are zero data entries');
1055. }
1056. $sum = $this->__sumdiff($n);
1057. if (PEAR:: isError($sum)) {
1058. return $sum;
1059. }
1060. return ($sum / $count);
1061. }/*}}}*/
1063. /**
1064. * Calculates the nth raw moment (m{n}) of a data set.
1065. *
1066. * The definition of a sample central moment is:
1067. *
1068. * m{n} = 1/N * SUM { xi^n }
1069. *
1070. * where: N = sample size, avg = sample mean.
1071. *
1072. * @access public
1073. * @param integer $n moment to calculate
1074. * @return mixed the numeric value of the moment on success, PEAR_Error otherwise
1075. */
1076. function sampleRawMoment($n) {/*{{{*/
1077. if (! is_int($n) || $n < 1) {
1078. return PEAR:: isError('moment must be a positive integer >= 1.');
1079. }
1081. $count = $this-> count();
1082. if (PEAR:: isError($count)) {
1083. return $count;
1084. }
1085. if ($count == 0) {
1086. return PEAR:: raiseError("Cannot calculate {$n}th raw moment, ".
1087. 'there are zero data entries.');
1088. }
1089. $sum = $this-> sumN($n);
1090. if (PEAR:: isError($sum)) {
1091. return $sum;
1092. }
1093. return ($sum / $count);
1094. }/*}}}*/
1097. /**
1098. * Calculates the coefficient of variation of a data set.
1099. * The coefficient of variation measures the spread of a set of data
1100. * as a proportion of its mean. It is often expressed as a percentage.
1101. * Handles cummulative data sets correctly
1102. *
1103. * @access public
1104. * @return mixed the coefficient of variation on success, a PEAR_Error object otherwise
1105. * @see stDev()
1106. * @see mean()
1107. * @see calc()
1108. */
1109. function coeffOfVariation() {/*{{{*/
1110. if (! array_key_exists('coeffOfVariation', $this->_calculatedValues)) {
1111. $mean = $this-> mean();
1112. if (PEAR:: isError($mean)) {
1113. return $mean;
1114. }
1115. if ($mean == 0.0) {
1116. return PEAR:: raiseError('cannot calculate the coefficient '.
1117. 'of variation, mean of sample is zero');
1118. }
1119. $stDev = $this-> stDev();
1120. if (PEAR:: isError($stDev)) {
1121. return $stDev;
1122. }
1124. $this->_calculatedValues['coeffOfVariation'] = $stDev / $mean;
1125. }
1126. return $this->_calculatedValues['coeffOfVariation'];
1127. }/*}}}*/
1129. /**
1130. * Calculates the standard error of the mean.
1131. * It is the standard deviation of the sampling distribution of
1132. * the mean. The formula is:
1133. *
1134. * S.E. Mean = SD / (N)^(1/2)
1135. *
1136. * This formula does not assume a normal distribution, and shows
1137. * that the size of the standard error of the mean is inversely
1138. * proportional to the square root of the sample size.
1139. *
1140. * @access public
1141. * @return mixed the standard error of the mean on success, a PEAR_Error object otherwise
1142. * @see stDev()
1143. * @see count()
1144. * @see calc()
1145. */
1146. function stdErrorOfMean() {/*{{{*/
1147. if (! array_key_exists('stdErrorOfMean', $this->_calculatedValues)) {
1148. $count = $this-> count();
1149. if (PEAR:: isError($count)) {
1150. return $count;
1151. }
1152. $stDev = $this-> stDev();
1153. if (PEAR:: isError($stDev)) {
1154. return $stDev;
1155. }
1156. $this->_calculatedValues['stdErrorOfMean'] = $stDev / sqrt($count);
1157. }
1158. return $this->_calculatedValues['stdErrorOfMean'];
1159. }/*}}}*/
1161. /**
1162. * Calculates the value frequency table of a data set.
1163. * Handles cummulative data sets correctly
1164. *
1165. * @access public
1166. * @return mixed an associative array of value=>frequency items on success, a PEAR_Error object otherwise
1167. * @see min()
1168. * @see max()
1169. * @see calc()
1170. */
1171. function frequency() {/*{{{*/
1172. if ($this->_data == null) {
1173. return PEAR:: raiseError('data has not been set');
1174. }
1175. if (! array_key_exists('frequency', $this->_calculatedValues)) {
1176. if ($this->_dataOption == STATS_DATA_CUMMULATIVE) {
1177. $freq = $this->_data;
1178. } else {
1179. $freq = array();
1180. foreach ($this->_data as $val) {
1181. $freq["$val"]++;
1182. }
1183. ksort($freq);
1184. }
1185. $this->_calculatedValues['frequency'] = $freq;
1186. }
1187. return $this->_calculatedValues['frequency'];
1188. }/*}}}*/
1190. /**
1191. * The quartiles are defined as the values that divide a sorted
1192. * data set into four equal-sized subsets, and correspond to the
1193. * 25th, 50th, and 75th percentiles.
1194. *
1195. * @access public
1196. * @return mixed an associative array of quartiles on success, a PEAR_Error otherwise
1197. * @see percentile()
1198. */
1199. function quartiles() {/*{{{*/
1200. if (! array_key_exists('quartiles', $this->_calculatedValues)) {
1201. $q1 = $this-> percentile(25);
1202. if (PEAR:: isError($q1)) {
1203. return $q1;
1204. }
1205. $q2 = $this-> percentile(50);
1206. if (PEAR:: isError($q2)) {
1207. return $q2;
1208. }
1209. $q3 = $this-> percentile(75);
1210. if (PEAR:: isError($q3)) {
1211. return $q3;
1212. }
1213. $this->_calculatedValues['quartiles'] = array (
1214. '25' => $q1,
1215. '50' => $q2,
1216. '75' => $q3
1217. );
1218. }
1219. return $this->_calculatedValues['quartiles'];
1220. }/*}}}*/
1222. /**
1223. * The interquartile mean is defined as the mean of the values left
1224. * after discarding the lower 25% and top 25% ranked values, i.e.:
1225. *
1226. * interquart mean = mean(<P(25),P(75)>)
1227. *
1228. * where: P = percentile
1229. *
1230. * @todo need to double check the equation
1231. * @access public
1232. * @return mixed a numeric value on success, a PEAR_Error otherwise
1233. * @see quartiles()
1234. */
1235. function interquartileMean() {/*{{{*/
1236. if (! array_key_exists('interquartileMean', $this->_calculatedValues)) {
1237. $quart = $this-> quartiles();
1238. if (PEAR:: isError($quart)) {
1239. return $quart;
1240. }
1241. $q3 = $quart['75'];
1242. $q1 = $quart['25'];
1243. $sum = 0;
1244. $n = 0;
1245. foreach ($this-> getData(true) as $val) {
1246. if ($val >= $q1 && $val <= $q3) {
1247. $sum += $val;
1248. ++$n;
1249. }
1250. }
1251. if ($n == 0) {
1252. return PEAR:: raiseError('error calculating interquartile mean, '.
1253. 'empty interquartile range of values.');
1254. }
1255. $this->_calculatedValues['interquartileMean'] = $sum / $n;
1256. }
1257. return $this->_calculatedValues['interquartileMean'];
1258. }/*}}}*/
1260. /**
1261. * The interquartile range is the distance between the 75th and 25th
1262. * percentiles. Basically the range of the middle 50% of the data set,
1263. * and thus is not affected by outliers or extreme values.
1264. *
1265. * interquart range = P(75) - P(25)
1266. *
1267. * where: P = percentile
1268. *
1269. * @access public
1270. * @return mixed a numeric value on success, a PEAR_Error otherwise
1271. * @see quartiles()
1272. */
1273. function interquartileRange() {/*{{{*/
1274. if (! array_key_exists('interquartileRange', $this->_calculatedValues)) {
1275. $quart = $this-> quartiles();
1276. if (PEAR:: isError($quart)) {
1277. return $quart;
1278. }
1279. $q3 = $quart['75'];
1280. $q1 = $quart['25'];
1281. $this->_calculatedValues['interquartileRange'] = $q3 - $q1;
1282. }
1283. return $this->_calculatedValues['interquartileRange'];
1284. }/*}}}*/
1286. /**
1287. * The quartile deviation is half of the interquartile range value
1288. *
1289. * quart dev = (P(75) - P(25)) / 2
1290. *
1291. * where: P = percentile
1292. *
1293. * @access public
1294. * @return mixed a numeric value on success, a PEAR_Error otherwise
1295. * @see quartiles()
1296. * @see interquartileRange()
1297. */
1298. function quartileDeviation() {/*{{{*/
1299. if (! array_key_exists('quartileDeviation', $this->_calculatedValues)) {
1300. $iqr = $this-> interquartileRange();
1301. if (PEAR:: isError($iqr)) {
1302. return $iqr;
1303. }
1304. $this->_calculatedValues['quartileDeviation'] = $iqr / 2;
1305. }
1306. return $this->_calculatedValues['quartileDeviation'];
1307. }/*}}}*/
1309. /**
1310. * The quartile variation coefficient is defines as follows:
1311. *
1312. * quart var coeff = 100 * (P(75) - P(25)) / (P(75) + P(25))
1313. *
1314. * where: P = percentile
1315. *
1316. * @todo need to double check the equation
1317. * @access public
1318. * @return mixed a numeric value on success, a PEAR_Error otherwise
1319. * @see quartiles()
1320. */
1321. function quartileVariationCoefficient() {/*{{{*/
1322. if (! array_key_exists('quartileVariationCoefficient', $this->_calculatedValues)) {
1323. $quart = $this-> quartiles();
1324. if (PEAR:: isError($quart)) {
1325. return $quart;
1326. }
1327. $q3 = $quart['75'];
1328. $q1 = $quart['25'];
1329. $d = $q3 - $q1;
1330. $s = $q3 + $q1;
1331. $this->_calculatedValues['quartileVariationCoefficient'] = 100 * $d / $s;
1332. }
1333. return $this->_calculatedValues['quartileVariationCoefficient'];
1334. }/*}}}*/
1336. /**
1337. * The quartile skewness coefficient (also known as Bowley Skewness),
1338. * is defined as follows:
1339. *
1340. * quart skewness coeff = (P(25) - 2*P(50) + P(75)) / (P(75) - P(25))
1341. *
1342. * where: P = percentile
1343. *
1344. * @todo need to double check the equation
1345. * @access public
1346. * @return mixed a numeric value on success, a PEAR_Error otherwise
1347. * @see quartiles()
1348. */
1349. function quartileSkewnessCoefficient() {/*{{{*/
1350. if (! array_key_exists('quartileSkewnessCoefficient', $this->_calculatedValues)) {
1351. $quart = $this-> quartiles();
1352. if (PEAR:: isError($quart)) {
1353. return $quart;
1354. }
1355. $q3 = $quart['75'];
1356. $q2 = $quart['50'];
1357. $q1 = $quart['25'];
1358. $d = $q3 - 2*$q2 + $q1;
1359. $s = $q3 - $q1;
1360. $this->_calculatedValues['quartileSkewnessCoefficient'] = $d / $s;
1361. }
1362. return $this->_calculatedValues['quartileSkewnessCoefficient'];
1363. }/*}}}*/
1365. /**
1366. * The pth percentile is the value such that p% of the a sorted data set
1367. * is smaller than it, and (100 - p)% of the data is larger.
1368. *
1369. * A quick algorithm to pick the appropriate value from a sorted data
1370. * set is as follows:
1371. *
1372. * - Count the number of values: n
1373. * - Calculate the position of the value in the data list: i = p * (n + 1)
1374. * - if i is an integer, return the data at that position
1375. * - if i < 1, return the minimum of the data set
1376. * - if i > n, return the maximum of the data set
1377. * - otherwise, average the entries at adjacent positions to i
1378. *
1379. * The median is the 50th percentile value.
1380. *
1381. * @todo need to double check generality of the algorithm
1382. *
1383. * @access public
1384. * @param numeric $p the percentile to estimate, e.g. 25 for 25th percentile
1385. * @return mixed a numeric value on success, a PEAR_Error otherwise
1386. * @see quartiles()
1387. * @see median()
1388. */
1389. function percentile($p) {/*{{{*/
1390. $count = $this-> count();
1391. if (PEAR:: isError($count)) {
1392. return $count;
1393. }
1394. if ($this->_dataOption == STATS_DATA_CUMMULATIVE) {
1395. $data =& $this->_dataExpanded;
1396. } else {
1397. $data =& $this->_data;
1398. }
1399. $obsidx = $p * ($count + 1) / 100;
1400. if ( intval($obsidx) == $obsidx) {
1401. return $data[($obsidx - 1)];
1402. } elseif ($obsidx < 1) {
1403. return $data[0];
1404. } elseif ($obsidx > $count) {
1405. return $data[($count - 1)];
1406. } else {
1407. $left = floor($obsidx - 1);
1408. $right = ceil($obsidx - 1);
1409. return ($data[$left] + $data[$right]) / 2;
1410. }
1411. }/*}}}*/
1413. // private methods
1415. /**
1416. * Utility function to calculate: SUM { (xi - mean)^n }
1417. *
1418. * @access private
1419. * @param numeric $power the exponent
1420. * @param optional double $mean the data set mean value
1421. * @return mixed the sum on success, a PEAR_Error object otherwise
1422. *
1423. * @see stDev()
1424. * @see variaceWithMean();
1425. * @see skewness();
1426. * @see kurtosis();
1427. */
1428. function __sumdiff($power, $mean=null) {/*{{{*/
1429. if ($this->_data == null) {
1430. return PEAR:: raiseError('data has not been set');
1431. }
1432. if ( is_null($mean)) {
1433. $mean = $this-> mean();
1434. if (PEAR:: isError($mean)) {
1435. return $mean;
1436. }
1437. }
1438. $sdiff = 0;
1439. if ($this->_dataOption == STATS_DATA_CUMMULATIVE) {
1440. foreach ($this->_data as $val=>$freq) {
1441. $sdiff += $freq * pow((double)($val - $mean), (double)$power);
1442. }
1443. } else {
1444. foreach ($this->_data as $val)
1445. $sdiff += pow((double)($val - $mean), (double)$power);
1446. }
1447. return $sdiff;
1448. }/*}}}*/
1450. /**
1451. * Utility function to calculate the variance with or without
1452. * a fixed mean
1453. *
1454. * @access private
1455. * @param $mean the fixed mean to use, null as default
1456. * @return mixed a numeric value on success, a PEAR_Error otherwise
1457. * @see variance()
1458. * @see varianceWithMean()
1459. */
1460. function __calcVariance($mean = null) {/*{{{*/
1461. if ($this->_data == null) {
1462. return PEAR:: raiseError('data has not been set');
1463. }
1464. $sumdiff2 = $this->__sumdiff(2, $mean);
1465. if (PEAR:: isError($sumdiff2)) {
1466. return $sumdiff2;
1467. }
1468. $count = $this-> count();
1469. if (PEAR:: isError($count)) {
1470. return $count;
1471. }
1472. if ($count == 1) {
1473. return PEAR:: raiseError('cannot calculate variance of a singe data point');
1474. }
1475. return ($sumdiff2 / ($count - 1));
1476. }/*}}}*/
1478. /**
1479. * Utility function to calculate the absolute deviation with or without
1480. * a fixed mean
1481. *
1482. * @access private
1483. * @param $mean the fixed mean to use, null as default
1484. * @return mixed a numeric value on success, a PEAR_Error otherwise
1485. * @see absDev()
1486. * @see absDevWithMean()
1487. */
1488. function __calcAbsoluteDeviation($mean = null) {/*{{{*/
1489. if ($this->_data == null) {
1490. return PEAR:: raiseError('data has not been set');
1491. }
1492. $count = $this-> count();
1493. if (PEAR:: isError($count)) {
1494. return $count;
1495. }
1496. $sumabsdev = $this->__sumabsdev($mean);
1497. if (PEAR:: isError($sumabsdev)) {
1498. return $sumabsdev;
1499. }
1500. return $sumabsdev / $count;
1501. }/*}}}*/
1503. /**
1504. * Utility function to calculate: SUM { | xi - mean | }
1505. *
1506. * @access private
1507. * @param optional double $mean the mean value for the set or population
1508. * @return mixed the sum on success, a PEAR_Error object otherwise
1509. *
1510. * @see absDev()
1511. * @see absDevWithMean()
1512. */
1513. function __sumabsdev($mean=null) {/*{{{*/
1514. if ($this->_data == null) {
1515. return PEAR:: raiseError('data has not been set');
1516. }
1517. if ( is_null($mean)) {
1518. $mean = $this-> mean();
1519. }
1520. $sdev = 0;
1521. if ($this->_dataOption == STATS_DATA_CUMMULATIVE) {
1522. foreach ($this->_data as $val=>$freq) {
1523. $sdev += $freq * abs($val - $mean);
1524. }
1525. } else {
1526. foreach ($this->_data as $val) {
1527. $sdev += abs($val - $mean);
1528. }
1529. }
1530. return $sdev;
1531. }/*}}}*/
1533. /**
1534. * Utility function to format a PEAR_Error to be used by calc(),
1535. * calcBasic() and calcFull()
1536. *
1537. * @access private
1538. * @param mixed $v value to be formatted
1539. * @param boolean $returnErrorObject whether the raw PEAR_Error (when true, default),
1540. * or only the error message will be returned (when false)
1541. * @return mixed if the value is a PEAR_Error object, and $useErrorObject
1542. * is false, then a string with the error message will be returned,
1543. * otherwise the value will not be modified and returned as passed.
1544. */
1545. function __format($v, $useErrorObject=true) {/*{{{*/
1546. if (PEAR:: isError($v) && $useErrorObject == false) {
1547. return $v->getMessage();
1548. } else {
1549. return $v;
1550. }
1551. }/*}}}*/
1553. /**
1554. * Utility function to validate the data and modify it
1555. * according to the current null handling option
1556. *
1557. * @access private
1558. * @return mixed true on success, a PEAR_Error object otherwise
1559. *
1560. * @see setData()
1561. */
1562. function _validate() {/*{{{*/
1563. $flag = ($this->_dataOption == STATS_DATA_CUMMULATIVE);
1564. foreach ($this->_data as $key=>$value) {
1565. $d = ($flag) ? $key : $value;
1566. $v = ($flag) ? $value : $key;
1567. if (! is_numeric($d)) {
1568. switch ($this->_nullOption) {
1569. case STATS_IGNORE_NULL :
1570. unset($this->_data["$key"]);
1571. break;
1572. case STATS_USE_NULL_AS_ZERO:
1573. if ($flag) {
1574. unset($this->_data["$key"]);
1575. $this->_data[0] += $v;
1576. } else {
1577. $this->_data[$key] = 0;
1578. }
1579. break;
1580. case STATS_REJECT_NULL :
1581. default:
1582. return PEAR:: raiseError('data rejected, contains NULL values');
1583. break;
1584. }
1585. }
1586. }
1587. if ($flag) {
1588. ksort($this->_data);
1589. $this->_dataExpanded = array();
1590. foreach ($this->_data as $val=>$freq) {
1591. $this->_dataExpanded = array_pad($this->_dataExpanded, count($this->_dataExpanded) + $freq, $val);
1592. }
1593. sort($this->_dataExpanded);
1594. } else {
1595. sort($this->_data);
1596. }
1597. return true;
1598. }/*}}}*/
1600. }/*}}}*/
1602. // vim: ts=4:sw=4:et:
1603. // vim6: fdl=1: fdm=marker:
1605. ?>

Documentation generated on Sun, 27 Feb 2011 16:34:11 -0800 by phpDocumentor 1.4.3