Outlier Detector
Flags numeric outliers using IQR or z-score style methods.
Function signature
ogDetectNumericOutliers(values = array(), options = array())
Categories
- Analytics and Reports
Parameters
valuesNumeric values.optionsOptional keys: method, threshold. Recognized keys: `method`, `threshold`.Return value
Short public-safe status message.
- method
- bounds
- outliers
- outlier_count
Compatibility
Existing function name and call order preserved; metadata signature corrected to source.
Minimum PHP version: 7.4
Security notes
Validate request method, identity, permissions, and caller-owned allowlists before use; keep secrets and internal paths out of public output.
Code
<?php
/*
* Copyright (c) 2026 Jeffery L. Paris <jparis@phpog.com>.
* Free for personal and internal use. Paid project use requires visible credit
* to Jeffery L. Paris. Corporate use requires a paid license fee unless a
* separate written license states otherwise.
*/
/**
* Flags numeric outliers using IQR or z-score style methods.
*
* @param array $values Numeric values.
* @param array $options Optional keys: method, threshold.
* @return array Outlier report with original indexes and reason text.
*/
function ogDetectNumericOutliers($values = array(), $options = array()) {
$result = array(
'success' => false,
'message' => '',
'data' => array()
);
if (!is_array($values)) {
$result['message'] = 'Values must be an array.';
return $result;
}
if (!is_array($options)) {
$options = array();
}
$method = 'iqr';
if (!empty($options['method'])) {
$method = strtolower((string)$options['method']);
}
$threshold = 1.5;
if (isset($options['threshold']) && is_numeric($options['threshold'])) {
$threshold = (float)$options['threshold'];
}
$records = array();
foreach ($values as $index => $value) {
if (is_numeric($value)) {
$records[] = array('index' => $index, 'value' => (float)$value);
}
}
if (count($records) < 4) {
$result['message'] = 'At least four numeric values are required for outlier detection.';
return $result;
}
$numeric_values = array();
foreach ($records as $record) {
$numeric_values[] = $record['value'];
}
sort($numeric_values, SORT_NUMERIC);
$outliers = array();
$bounds = array();
if ($method == 'zscore') {
$average = array_sum($numeric_values) / count($numeric_values);
$variance_total = 0;
foreach ($numeric_values as $value) {
$variance_total += pow($value - $average, 2);
}
$standard_deviation = sqrt($variance_total / count($numeric_values));
if ($standard_deviation == 0) {
$standard_deviation = 1;
}
foreach ($records as $record) {
$score = abs(($record['value'] - $average) / $standard_deviation);
if ($score > $threshold) {
$outliers[] = array('index' => $record['index'], 'value' => $record['value'], 'reason' => 'zscore:' . $score);
}
}
$bounds = array('average' => $average, 'standard_deviation' => $standard_deviation, 'threshold' => $threshold);
} else {
$q1_rank = 0.25 * (count($numeric_values) - 1);
$q1_lower = (int)floor($q1_rank);
$q1_upper = (int)ceil($q1_rank);
$q1_weight = $q1_rank - $q1_lower;
$q1 = $numeric_values[$q1_lower];
if ($q1_upper != $q1_lower) {
$q1 = $numeric_values[$q1_lower] + (($numeric_values[$q1_upper] - $numeric_values[$q1_lower]) * $q1_weight);
}
$q3_rank = 0.75 * (count($numeric_values) - 1);
$q3_lower = (int)floor($q3_rank);
$q3_upper = (int)ceil($q3_rank);
$q3_weight = $q3_rank - $q3_lower;
$q3 = $numeric_values[$q3_lower];
if ($q3_upper != $q3_lower) {
$q3 = $numeric_values[$q3_lower] + (($numeric_values[$q3_upper] - $numeric_values[$q3_lower]) * $q3_weight);
}
$iqr = $q3 - $q1;
$low = $q1 - ($iqr * $threshold);
$high = $q3 + ($iqr * $threshold);
foreach ($records as $record) {
if ($record['value'] < $low || $record['value'] > $high) {
$outliers[] = array('index' => $record['index'], 'value' => $record['value'], 'reason' => 'outside_iqr_bounds');
}
}
$bounds = array('q1' => $q1, 'q3' => $q3, 'iqr' => $iqr, 'low' => $low, 'high' => $high);
}
$result['success'] = true;
$result['message'] = 'Outlier detection completed.';
$result['data'] = array(
'method' => $method,
'bounds' => $bounds,
'outliers' => $outliers,
'outlier_count' => count($outliers)
);
return $result;
}