~hartmut-php/eventum/no-mysql-functions

« back to all changes in this revision

Viewing changes to lib/pear/Math/Stats.php

  • Committer: Elan Ruusamäe
  • Date: 2011-02-20 22:32:30 UTC
  • Revision ID: glen@delfi.ee-20110220223230-nka08x7zqa7k6h7p
update pear package Math_Stats to 0.8.5

Show diffs side-by-side

added added

removed removed

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