PageRenderTime 72ms CodeModel.GetById 12ms app.highlight 51ms RepoModel.GetById 1ms app.codeStats 1ms

/PHPExcel/Shared/JAMA/examples/Stats.php

https://bitbucket.org/nfredricks/wp-employee-time
PHP | 1605 lines | 834 code | 72 blank | 699 comment | 226 complexity | dfc48d3fa9118e8f89a9f975ea53fa64 MD5 | raw file

Large files files are truncated, but you can click here to view the full 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
  22include_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*/
  32define('STATS_BASIC', 1);
  33/**
  34* STATS_FULL to generate also higher moments, mode, median, etc.
  35*/
  36define('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*/
  44define('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*/
  51define('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*/
  59define('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*/
  64define('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*/
  69define('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*/
 119class 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                            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
 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($stDev, 3)));
 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($stDev, 4))) - 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 % 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
 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 + $min) / 2);
 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 , 1 / $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 += 1 / $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(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
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 + 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
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 PE…

Large files files are truncated, but you can click here to view the full file