Math_Stats
[ class tree: Math_Stats ] [ index: Math_Stats ] [ all elements ]

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. //
  21.  
  22. include_once 'PEAR.php';
  23.  
  24. /**
  25. @package Math_Stats
  26. */
  27.  
  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. /*}}}*/
  38.  
  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. /*}}}*/
  53.  
  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. /*}}}*/
  71.  
  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 /*{{{*/
  121.  
  122.     /**
  123.      * The simple or cummulative data set.
  124.      * Null by default.
  125.      *
  126.      * @access  private
  127.      * @var array 
  128.      */
  129.     public $_data = null;
  130.  
  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;
  139.  
  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;
  148.  
  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;
  157.  
  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();
  166.  
  167.     /*}}}*/
  168.  
  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.     }/*}}}*/
  179.  
  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.     }/*}}}*/
  207.  
  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.     }/*}}}*/
  227.  
  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.     }/*}}}*/
  247.  
  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.     }/*}}}*/
  285.  
  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.     }/*}}}*/
  314.  
  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.     }/*}}}*/
  338.  
  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.     }/*}}}*/
  362.  
  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.                             => $this->__format($this->sampleCentralMoment(1)$returnErrorObject),
  396.                             => $this->__format($this->sampleCentralMoment(2)$returnErrorObject),
  397.                             => $this->__format($this->sampleCentralMoment(3)$returnErrorObject),
  398.                             => $this->__format($this->sampleCentralMoment(4)$returnErrorObject),
  399.                             => $this->__format($this->sampleCentralMoment(5)$returnErrorObject)
  400.                             ),
  401.                 'sample_raw_moments' => array (
  402.                             => $this->__format($this->sampleRawMoment(1)$returnErrorObject),
  403.                             => $this->__format($this->sampleRawMoment(2)$returnErrorObject),
  404.                             => $this->__format($this->sampleRawMoment(3)$returnErrorObject),
  405.                             => $this->__format($this->sampleRawMoment(4)$returnErrorObject),
  406.                             => $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.  
  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.     }/*}}}*/
  441.  
  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.     }/*}}}*/
  465.  
  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.     }/*}}}*/
  487.  
  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.     }/*}}}*/
  509.  
  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.     }/*}}}*/
  537.  
  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.     }/*}}}*/
  557.  
  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;
  588.  
  589.     }/*}}}*/
  590.  
  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.     }/*}}}*/
  613.  
  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.     }/*}}}*/
  638.  
  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'];
  658.  
  659.     }/*}}}*/
  660.  
  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.     }/*}}}*/
  681.  
  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.     }/*}}}*/
  701.  
  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.     }/*}}}*/
  718.  
  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.     }/*}}}*/
  738.  
  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.     }/*}}}*/
  760.  
  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.     }/*}}}*/
  776.  
  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($stDev3)));
  810.         }
  811.         return $this->_calculatedValues['skewness'];
  812.     }/*}}}*/
  813.  
  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($stDev4))) 3;
  847.         }
  848.         return $this->_calculatedValues['kurtosis'];
  849.     }/*}}}*/
  850.  
  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 == 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.  
  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.     }/*}}}*/
  928.  
  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 $min2);
  951.         }
  952.         return $this->_calculatedValues['midrange'];
  953.     }/*}}}*/
  954.  
  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 $count);
  982.         }
  983.         return $this->_calculatedValues['geometricMean'];
  984.     }/*}}}*/
  985.  
  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 += $val;
  1020.                 }
  1021.             }
  1022.             $this->_calculatedValues['harmonicMean'$count $invsum;
  1023.         }
  1024.         return $this->_calculatedValues['harmonicMean'];
  1025.     }/*}}}*/
  1026.  
  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.         }
  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.  
  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.         }
  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.  
  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.             }
  1123.  
  1124.             $this->_calculatedValues['coeffOfVariation'$stDev $mean;
  1125.         }
  1126.         return $this->_calculatedValues['coeffOfVariation'];
  1127.     }/*}}}*/
  1128.  
  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.     }/*}}}*/
  1160.  
  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.     }/*}}}*/
  1189.  
  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.     }/*}}}*/
  1221.  
  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(trueas $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.  
  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.     }/*}}}*/
  1285.  
  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.     }/*}}}*/
  1308.  
  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.     }/*}}}*/
  1335.  
  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.     }/*}}}*/
  1364.  
  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 1100;
  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.  
  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.     }/*}}}*/
  1449.  
  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.     }/*}}}*/
  1477.  
  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.     }/*}}}*/
  1502.  
  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.     }/*}}}*/
  1532.  
  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.     }/*}}}*/
  1552.  
  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[$key0;
  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->_dataExpandedcount($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. ?>

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