ILIAS  eassessment Revision 61809
 All Data Structures Namespaces Files Functions Variables Groups Pages
Stats.php
Go to the documentation of this file.
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 //
21 
22 include_once 'PEAR.php';
23 
28 // Constants for defining the statistics to calculate /*{{{*/
32 define('STATS_BASIC', 1);
36 define('STATS_FULL', 2);
37 /*}}}*/
38 
39 // Constants describing the data set format /*{{{*/
44 define('STATS_DATA_SIMPLE', 0);
51 define('STATS_DATA_CUMMULATIVE', 1);
52 /*}}}*/
53 
54 // Constants defining how to handle nulls /*{{{*/
59 define('STATS_REJECT_NULL', -1);
64 define('STATS_IGNORE_NULL', -2);
69 define('STATS_USE_NULL_AS_ZERO', -3);
70 /*}}}*/
71 
119 class Base {/*{{{*/
120  // properties /*{{{*/
121 
129  public $_data = null;
130 
138  public $_dataExpanded = null;
139 
147  public $_dataOption = null;
148 
156  public $_nullOption;
157 
165  public $_calculatedValues = array();
166 
167  /*}}}*/
168 
176  function Math_Stats($nullOption=STATS_REJECT_NULL) {/*{{{*/
177  $this->_nullOption = $nullOption;
178  }/*}}}*/
179 
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  }/*}}}*/
207 
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  }/*}}}*/
227 
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  }/*}}}*/
247 
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  }/*}}}*/
285 
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  }/*}}}*/
314 
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  }/*}}}*/
338 
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  }/*}}}*/
362 
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  }/*}}}*/
417 
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  }/*}}}*/
441 
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  }/*}}}*/
465 
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  }/*}}}*/
487 
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  }/*}}}*/
509 
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  }/*}}}*/
537 
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  }/*}}}*/
557 
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;
588 
589  }/*}}}*/
590 
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  }/*}}}*/
613 
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  }/*}}}*/
638 
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'];
658 
659  }/*}}}*/
660 
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  }/*}}}*/
681 
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  }/*}}}*/
701 
715  function varianceWithMean($mean) {/*{{{*/
716  return $this->__calcVariance($mean);
717  }/*}}}*/
718 
731  function stDevWithMean($mean) {/*{{{*/
732  $varianceWM = $this->varianceWithMean($mean);
733  if (PEAR::isError($varianceWM)) {
734  return $varianceWM;
735  }
736  return sqrt($varianceWM);
737  }/*}}}*/
738 
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  }/*}}}*/
760 
773  function absDevWithMean($mean) {/*{{{*/
774  return $this->__calcAbsoluteDeviation($mean);
775  }/*}}}*/
776 
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  }/*}}}*/
813 
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  }/*}}}*/
850 
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  }/*}}}*/
888 
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  }/*}}}*/
928 
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  }/*}}}*/
954 
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  }/*}}}*/
985 
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  }/*}}}*/
1026 
1040  function sampleCentralMoment($n) {/*{{{*/
1041  if (!is_int($n) || $n < 1) {
1042  return PEAR::isError('moment must be a positive integer >= 1.');
1043  }
1044 
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  }/*}}}*/
1062 
1076  function sampleRawMoment($n) {/*{{{*/
1077  if (!is_int($n) || $n < 1) {
1078  return PEAR::isError('moment must be a positive integer >= 1.');
1079  }
1080 
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  }/*}}}*/
1095 
1096 
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  }
1123 
1124  $this->_calculatedValues['coeffOfVariation'] = $stDev / $mean;
1125  }
1126  return $this->_calculatedValues['coeffOfVariation'];
1127  }/*}}}*/
1128 
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  }/*}}}*/
1160 
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  }/*}}}*/
1189 
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  }/*}}}*/
1221 
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  }/*}}}*/
1259 
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  }/*}}}*/
1285 
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  }/*}}}*/
1308 
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  }/*}}}*/
1335 
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  }/*}}}*/
1364 
1389  function percentile($p) {/*{{{*/
1390  $count = $this->count();
1391  if (PEAR::isError($count)) {
1392  return $count;
1393  }
1394  if ($this->_dataOption == STATS_DATA_CUMMULATIVE) {
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  }/*}}}*/
1412 
1413  // private methods
1414 
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  }/*}}}*/
1449 
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  }/*}}}*/
1477 
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  }/*}}}*/
1502 
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  }/*}}}*/
1532 
1545  function __format($v, $useErrorObject=true) {/*{{{*/
1546  if (PEAR::isError($v) && $useErrorObject == false) {
1547  return $v->getMessage();
1548  } else {
1549  return $v;
1550  }
1551  }/*}}}*/
1552 
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;
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  }/*}}}*/
1599 
1600 }/*}}}*/
1601 
1602 // vim: ts=4:sw=4:et:
1603 // vim6: fdl=1: fdm=marker:
1604 
1605 ?>