30
30
* STATS_BASIC to generate the basic descriptive statistics
32
define('STATS_BASIC', 1);
32
define("STATS_BASIC", 1);
34
34
* STATS_FULL to generate also higher moments, mode, median, etc.
36
define('STATS_FULL', 2);
36
define("STATS_FULL", 2);
39
39
// Constants describing the data set format /*{{{*/
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);
44
define('STATS_DATA_SIMPLE', 0);
44
define("STATS_DATA_SIMPLE", 0);
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)
51
define('STATS_DATA_CUMMULATIVE', 1);
51
define("STATS_DATA_CUMMULATIVE", 1);
54
54
// Constants defining how to handle nulls /*{{{*/
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.
59
define('STATS_REJECT_NULL', -1);
59
define("STATS_REJECT_NULL", -1);
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.
64
define('STATS_IGNORE_NULL', -2);
64
define("STATS_IGNORE_NULL", -2);
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.
69
define('STATS_USE_NULL_AS_ZERO', -3);
69
define("STATS_USE_NULL_AS_ZERO", -3);
240
212
$this->_nullOption = $nullOption;
243
return PEAR::raiseError('invalid null handling option expecting: '.
244
'STATS_REJECT_NULL, STATS_IGNORE_NULL or STATS_USE_NULL_AS_ZERO');
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.
254
* @return mixed true on success, a PEAR_Error object otherwise
259
function studentize() {/*{{{*/
260
$mean = $this->mean();
261
if (PEAR::isError($mean)) {
264
$std = $this->stDev();
265
if (PEAR::isError($std)) {
269
return PEAR::raiseError('cannot studentize data, standard deviation is zero.');
272
if ($this->_dataOption == STATS_DATA_CUMMULATIVE) {
273
foreach ($this->_data as $val=>$freq) {
274
$newval = ($val - $mean) / $std;
275
$arr["$newval"] = $freq;
278
foreach ($this->_data as $val) {
279
$newval = ($val - $mean) / $std;
283
return $this->setData($arr, $this->_dataOption);
287
* Transforms the data by substracting each entry from the mean.
288
* This will reset all pre-calculated values to their original (unset) defaults.
291
* @return mixed true on success, a PEAR_Error object otherwise
295
function center() {/*{{{*/
296
$mean = $this->mean();
297
if (PEAR::isError($mean)) {
301
if ($this->_dataOption == STATS_DATA_CUMMULATIVE) {
302
foreach ($this->_data as $val=>$freq) {
303
$newval = $val - $mean;
304
$arr["$newval"] = $freq;
307
foreach ($this->_data as $val) {
308
$newval = $val - $mean;
312
return $this->setData($arr, $this->_dataOption);
215
return PEAR::raiseError("invalid null handling option expecting: ".
216
"STATS_REJECT_NULL, STATS_IGNORE_NULL or STATS_USE_NULL_AS_ZERO");
316
221
* Calculates the basic or full statistics for the data set
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()
326
function calc($mode, $returnErrorObject=true) {/*{{{*/
327
if ($this->_data == null) {
328
return PEAR::raiseError('data has not been set');
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);
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()
243
} else if ($mode == STATS_FULL) {
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)
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)
275
"frequency" => $this->frequency()
335
return PEAR::raiseError('incorrect mode, expected STATS_BASIC or STATS_FULL');
278
return PEAR::raiseError("incorrect mode, expected STATS_BASIC or STATS_FULL");
340
283
* Calculates a basic set of statistics
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
347
288
* @see calcFull()
349
function calcBasic($returnErrorObject=true) {/*{{{*/
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)
290
function calcBasic() {/*{{{*/
291
return $this->calc(STATS_BASIC);
364
295
* Calculates a full set of statistics
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
371
300
* @see calcBasic()
373
function calcFull($returnErrorObject=true) {/*{{{*/
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)
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)
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)
302
function calcFull() {/*{{{*/
303
return $this->calc(STATS_FULL);
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
521
381
function sumN($n) {/*{{{*/
522
if ($this->_data == null) {
523
return PEAR::raiseError('data has not been set');
382
if ($this->_data == null)
383
return PEAR::raiseError("data has not been set");
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);
531
foreach($this->_data as $val) {
389
foreach($this->_data as $val)
532
390
$sumN += pow((double)$val, (double)$n);
539
* Calculates PROD { (xi) }, (the product of all observations)
540
* Handles cummulative data sets correctly
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
548
function product() {/*{{{*/
549
if (!array_key_exists('product', $this->_calculatedValues)) {
550
$product = $this->productN(1);
551
if (PEAR::isError($product)) {
554
$this->_calculatedValues['product'] = $product;
557
return $this->_calculatedValues['product'];
561
* Calculates PROD { (xi)^n }, which is the product of all observations
562
* Handles cummulative data sets correctly
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
571
function productN($n) {/*{{{*/
572
if ($this->_data == null) {
573
return PEAR::raiseError('data has not been set');
577
if ($this->_dataOption == STATS_DATA_CUMMULATIVE) {
578
foreach($this->_data as $val=>$freq) {
582
$prodN *= $freq * pow((double)$val, (double)$n);
583
if ($prodN > 10000*$n) {
589
foreach($this->_data as $val) {
593
$prodN *= pow((double)$val, (double)$n);
594
if ($prodN > 10*$n) {
600
if (!empty($partial)) {
602
// try to reduce to a single value
604
foreach ($partial as $val) {
606
// cannot reduce, return an array
607
if (is_infinite($tmp)) {
619
396
* Calculates the number of data points in the set
620
397
* Handles cummulative data sets correctly
623
* @return mixed the count on success, a PEAR_Error object otherwise
400
* @return mixed the count on success, a PEAR_Error object otherwise
626
403
function count() {/*{{{*/
627
if ($this->_data == null) {
628
return PEAR::raiseError('data has not been set');
630
if (!array_key_exists('count', $this->_calculatedValues)) {
631
if ($this->_dataOption == STATS_DATA_CUMMULATIVE) {
632
$count = count($this->_dataExpanded);
634
$count = count($this->_data);
636
$this->_calculatedValues['count'] = $count;
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)
410
$count = count($this->_data);
920
621
* Handles cummulative data sets correctly
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()
927
628
function mode() {/*{{{*/
928
if ($this->_data == null) {
929
return PEAR::raiseError('data has not been set');
931
if (!array_key_exists('mode', $this->_calculatedValues)) {
932
if ($this->_dataOption == STATS_DATA_CUMMULATIVE) {
935
$arr = $this->frequency();
939
foreach ($arr as $val=>$freq) {
951
$this->_calculatedValues['mode'] = $mode;
953
return $this->_calculatedValues['mode'];
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
962
* @return mixed the midrange value on success, a PEAR_Error object otherwise
967
function midrange() {/*{{{*/
968
if (!array_key_exists('midrange', $this->_calculatedValues)) {
970
if (PEAR::isError($min)) {
974
if (PEAR::isError($max)) {
977
$this->_calculatedValues['midrange'] = (($max + $min) / 2);
979
return $this->_calculatedValues['midrange'];
983
* Calculates the geometrical mean of the data points in the set
984
* Handles cummulative data sets correctly
987
* @return mixed the geometrical mean value on success, a PEAR_Error object otherwise
992
function geometricMean() {/*{{{*/
993
if (!array_key_exists('geometricMean', $this->_calculatedValues)) {
994
$count = $this->count();
995
if (PEAR::isError($count)) {
998
$prod = $this->product();
999
if (PEAR::isError($prod)) {
1002
if (is_array($prod)) {
1004
foreach($prod as $val) {
1005
$geomMean *= pow($val, 1/$count);
1007
$this->_calculatedValues['geometricMean'] = $geomMean;
1013
return PEAR::raiseError('The product of the data set is negative, geometric mean undefined.');
1015
$this->_calculatedValues['geometricMean'] = pow($prod , 1 / $count);
1018
return $this->_calculatedValues['geometricMean'];
1022
* Calculates the harmonic mean of the data points in the set
1023
* Handles cummulative data sets correctly
1026
* @return mixed the harmonic mean value on success, a PEAR_Error object otherwise
1030
function harmonicMean() {/*{{{*/
1031
if ($this->_data == null) {
1032
return PEAR::raiseError('data has not been set');
1034
if (!array_key_exists('harmonicMean', $this->_calculatedValues)) {
1035
$count = $this->count();
1036
if (PEAR::isError($count)) {
1040
if ($this->_dataOption == STATS_DATA_CUMMULATIVE) {
1041
foreach($this->_data as $val=>$freq) {
1043
return PEAR::raiseError('cannot calculate a '.
1044
'harmonic mean with data values of zero.');
1046
$invsum += $freq / $val;
1049
foreach($this->_data as $val) {
1051
return PEAR::raiseError('cannot calculate a '.
1052
'harmonic mean with data values of zero.');
1054
$invsum += 1 / $val;
1057
$this->_calculatedValues['harmonicMean'] = $count / $invsum;
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)
634
$arr = $this->frequency();
637
foreach ($arr as $val=>$freq) {
1128
700
return ($sum / $count);
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
709
* @return mixed the midrange value on success, a PEAR_Error object otherwise
714
function midrange() {/*{{{*/
715
if ($this->_data == null)
716
return PEAR::raiseError("data has not been set");
717
return (($this->max() + $this->min()) / 2);
721
* Calculates the value frequency table of a data set.
722
* Handles cummulative data sets correctly
725
* @return mixed an associative array of value=>frequency items on success, a PEAR_Error object otherwise
730
function frequency() {/*{{{*/
731
if ($this->_data == null)
732
return PEAR::raiseError("data has not been set");
733
if ($this->_dataOption == STATS_DATA_CUMMULATIVE) {
737
foreach ($this->_data as $val)
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
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
1144
755
function coeffOfVariation() {/*{{{*/
1145
if (!array_key_exists('coeffOfVariation', $this->_calculatedValues)) {
1146
$mean = $this->mean();
1147
if (PEAR::isError($mean)) {
1151
return PEAR::raiseError('cannot calculate the coefficient '.
1152
'of variation, mean of sample is zero');
1154
$stDev = $this->stDev();
1155
if (PEAR::isError($stDev)) {
1159
$this->_calculatedValues['coeffOfVariation'] = $stDev / $mean;
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();
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.
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
1181
778
function stdErrorOfMean() {/*{{{*/
1182
if (!array_key_exists('stdErrorOfMean', $this->_calculatedValues)) {
1183
$count = $this->count();
1184
if (PEAR::isError($count)) {
1187
$stDev = $this->stDev();
1188
if (PEAR::isError($stDev)) {
1191
$this->_calculatedValues['stdErrorOfMean'] = $stDev / sqrt($count);
1193
return $this->_calculatedValues['stdErrorOfMean'];
1197
* Calculates the value frequency table of a data set.
1198
* Handles cummulative data sets correctly
1201
* @return mixed an associative array of value=>frequency items on success, a PEAR_Error object otherwise
1206
function frequency() {/*{{{*/
1207
if ($this->_data == null) {
1208
return PEAR::raiseError('data has not been set');
1210
if (!array_key_exists('frequency', $this->_calculatedValues)) {
1211
if ($this->_dataOption == STATS_DATA_CUMMULATIVE) {
1212
$freq = $this->_data;
1215
foreach ($this->_data as $val) {
1220
$this->_calculatedValues['frequency'] = $freq;
1222
return $this->_calculatedValues['frequency'];
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.
1231
* @return mixed an associative array of quartiles on success, a PEAR_Error otherwise
1234
function quartiles() {/*{{{*/
1235
if (!array_key_exists('quartiles', $this->_calculatedValues)) {
1236
$q1 = $this->percentile(25);
1237
if (PEAR::isError($q1)) {
1240
$q2 = $this->percentile(50);
1241
if (PEAR::isError($q2)) {
1244
$q3 = $this->percentile(75);
1245
if (PEAR::isError($q3)) {
1248
$this->_calculatedValues['quartiles'] = array (
1254
return $this->_calculatedValues['quartiles'];
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.:
1261
* interquart mean = mean(<P(25),P(75)>)
1263
* where: P = percentile
1265
* @todo need to double check the equation
1267
* @return mixed a numeric value on success, a PEAR_Error otherwise
1270
function interquartileMean() {/*{{{*/
1271
if (!array_key_exists('interquartileMean', $this->_calculatedValues)) {
1272
$quart = $this->quartiles();
1273
if (PEAR::isError($quart)) {
1280
foreach ($this->getData(true) as $val) {
1281
if ($val >= $q1 && $val <= $q3) {
1287
return PEAR::raiseError('error calculating interquartile mean, '.
1288
'empty interquartile range of values.');
1290
$this->_calculatedValues['interquartileMean'] = $sum / $n;
1292
return $this->_calculatedValues['interquartileMean'];
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.
1300
* interquart range = P(75) - P(25)
1302
* where: P = percentile
1305
* @return mixed a numeric value on success, a PEAR_Error otherwise
1308
function interquartileRange() {/*{{{*/
1309
if (!array_key_exists('interquartileRange', $this->_calculatedValues)) {
1310
$quart = $this->quartiles();
1311
if (PEAR::isError($quart)) {
1316
$this->_calculatedValues['interquartileRange'] = $q3 - $q1;
1318
return $this->_calculatedValues['interquartileRange'];
1322
* The quartile deviation is half of the interquartile range value
1324
* quart dev = (P(75) - P(25)) / 2
1326
* where: P = percentile
1329
* @return mixed a numeric value on success, a PEAR_Error otherwise
1331
* @see interquartileRange()
1333
function quartileDeviation() {/*{{{*/
1334
if (!array_key_exists('quartileDeviation', $this->_calculatedValues)) {
1335
$iqr = $this->interquartileRange();
1336
if (PEAR::isError($iqr)) {
1339
$this->_calculatedValues['quartileDeviation'] = $iqr / 2;
1341
return $this->_calculatedValues['quartileDeviation'];
1345
* The quartile variation coefficient is defines as follows:
1347
* quart var coeff = 100 * (P(75) - P(25)) / (P(75) + P(25))
1349
* where: P = percentile
1351
* @todo need to double check the equation
1353
* @return mixed a numeric value on success, a PEAR_Error otherwise
1356
function quartileVariationCoefficient() {/*{{{*/
1357
if (!array_key_exists('quartileVariationCoefficient', $this->_calculatedValues)) {
1358
$quart = $this->quartiles();
1359
if (PEAR::isError($quart)) {
1366
$this->_calculatedValues['quartileVariationCoefficient'] = 100 * $d / $s;
1368
return $this->_calculatedValues['quartileVariationCoefficient'];
1372
* The quartile skewness coefficient (also known as Bowley Skewness),
1373
* is defined as follows:
1375
* quart skewness coeff = (P(25) - 2*P(50) + P(75)) / (P(75) - P(25))
1377
* where: P = percentile
1379
* @todo need to double check the equation
1381
* @return mixed a numeric value on success, a PEAR_Error otherwise
1384
function quartileSkewnessCoefficient() {/*{{{*/
1385
if (!array_key_exists('quartileSkewnessCoefficient', $this->_calculatedValues)) {
1386
$quart = $this->quartiles();
1387
if (PEAR::isError($quart)) {
1393
$d = $q3 - 2*$q2 + $q1;
1395
$this->_calculatedValues['quartileSkewnessCoefficient'] = $d / $s;
1397
return $this->_calculatedValues['quartileSkewnessCoefficient'];
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.
1404
* A quick algorithm to pick the appropriate value from a sorted data
1405
* set is as follows:
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
1414
* The median is the 50th percentile value.
1416
* @todo need to double check generality of the algorithm
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
1424
function percentile($p) {/*{{{*/
1425
$count = $this->count();
1426
if (PEAR::isError($count)) {
1429
if ($this->_dataOption == STATS_DATA_CUMMULATIVE) {
1430
$data =& $this->_dataExpanded;
1432
$data =& $this->_data;
1434
$obsidx = $p * ($count + 1) / 100;
1435
if (intval($obsidx) == $obsidx) {
1436
return $data[($obsidx - 1)];
1437
} elseif ($obsidx < 1) {
1439
} elseif ($obsidx > $count) {
1440
return $data[($count - 1)];
1442
$left = floor($obsidx - 1);
1443
$right = ceil($obsidx - 1);
1444
return ($data[$left] + $data[$right]) / 2;
779
if ($this->_data == null)
780
return PEAR::raiseError("data has not been set");
781
return $this->stDev() / sqrt($this->count());
1451
785
* Utility function to calculate: SUM { (xi - mean)^n }
1453
787
* @access private
1454
788
* @param numeric $power the exponent
1455
789
* @param optional double $mean the data set mean value
1486
* Utility function to calculate the variance with or without
1490
* @param $mean the fixed mean to use, null as default
1491
* @return mixed a numeric value on success, a PEAR_Error otherwise
1493
* @see varianceWithMean()
1495
function __calcVariance($mean = null) {/*{{{*/
1496
if ($this->_data == null) {
1497
return PEAR::raiseError('data has not been set');
1499
$sumdiff2 = $this->__sumdiff(2, $mean);
1500
if (PEAR::isError($sumdiff2)) {
1503
$count = $this->count();
1504
if (PEAR::isError($count)) {
1508
return PEAR::raiseError('cannot calculate variance of a singe data point');
1510
return ($sumdiff2 / ($count - 1));
1514
* Utility function to calculate the absolute deviation with or without
1518
* @param $mean the fixed mean to use, null as default
1519
* @return mixed a numeric value on success, a PEAR_Error otherwise
1521
* @see absDevWithMean()
1523
function __calcAbsoluteDeviation($mean = null) {/*{{{*/
1524
if ($this->_data == null) {
1525
return PEAR::raiseError('data has not been set');
1527
$count = $this->count();
1528
if (PEAR::isError($count)) {
1531
$sumabsdev = $this->__sumabsdev($mean);
1532
if (PEAR::isError($sumabsdev)) {
1535
return $sumabsdev / $count;
1539
814
* Utility function to calculate: SUM { | xi - mean | }
1541
816
* @access private
1546
821
* @see absDevWithMean()
1548
823
function __sumabsdev($mean=null) {/*{{{*/
1549
if ($this->_data == null) {
1550
return PEAR::raiseError('data has not been set');
1552
if (is_null($mean)) {
824
if ($this->_data == null)
825
return PEAR::raiseError("data has not been set");
1553
827
$mean = $this->mean();
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);
1561
foreach ($this->_data as $val) {
833
foreach ($this->_data as $val)
1562
834
$sdev += abs($val - $mean);
1569
* Utility function to format a PEAR_Error to be used by calc(),
1570
* calcBasic() and calcFull()
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.
1580
function __format($v, $useErrorObject=true) {/*{{{*/
1581
if (PEAR::isError($v) && $useErrorObject == false) {
1582
return $v->getMessage();
1589
840
* Utility function to validate the data and modify it
1590
841
* according to the current null handling option
1592
843
* @access private
1593
844
* @return mixed true on success, a PEAR_Error object otherwise
1595
846
* @see setData()
1597
848
function _validate() {/*{{{*/