在 PHP 中的数字数组中查找并删除异常值/异常
Finding and removing outliers / anomalies in an array of numbers in PHP
我在 PHP 中有这样一组数字:
$numbers = [
0.0021030494216614,
0.0019940179461615,
0.0079320972662613,
0.0040485829959514,
0.0079320972662613,
0.0021030494216614,
0.0019940179461615,
0.0079320972662613,
0.0040485829959514,
0.0079320972662613,
0.0021030494216614,
1.1002979145978,
85.230769230769,
6.5833333333333,
0.015673981191223
];
在 PHP 中,我试图找出这个数组中的离群值/异常值。
如您所见,异常是
1.1002979145978,
85.230769230769,
6.5833333333333,
0.015673981191223
我正在尝试查找并删除任何数组中的异常。
这是我的代码
function remove_anomalies($dataset, $magnitude = 1) {
$count = count($dataset);
$mean = array_sum($dataset) / $count;
$deviation = sqrt(array_sum(array_map("sd_square", $dataset, array_fill(0, $count, $mean))) / $count) * $magnitude;
return array_filter($dataset, function($x) use ($mean, $deviation) { return ($x <= $mean + $deviation && $x >= $mean - $deviation); });
}
function sd_square($x, $mean) {
return pow($x - $mean, 2);
}
但是,当我将 $numbers
数组放入其中时,当那里明显有更多异常值时,它只会给我 [85.230769230769]
作为异常值。
我试过摆弄 $magnitude
但没有任何改善。
此处显示的算法使用平均绝对偏差 (MAD) 一种可靠的度量来识别异常值。
所有距离超过MAD倍数的元素被连续移除,重新计算MAD。
function median(array $data)
{
if(($count = count($data)) < 1) return false;
sort($data, SORT_NUMERIC);
$mid = (int)($count/2);
if($count % 2) return $data[$mid];
return ($data[$mid] + $data[$mid-1])/2;
}
function mad(array $data)
{
if(($count = count($data)) < 1) return false;
$median = median($data);
$mad = 0.0;
foreach($data as $xi) {
$mad += abs($xi - $median);
}
return $mad/$count;
}
function cleanMedian(array &$data, $fac = 2.0)
{
do{
$unsetCount = 0;
$median = median($data);
$mad = mad($data) * $fac;
//remove all with diff > $mad
foreach($data as $idx => $val){
if(abs($val - $median) > $mad){
unset($data[$idx]);
++$unsetCount;
}
}
} while($unsetCount > 0);
}
使用方法:
$data = [
//..
];
cleanMedian($data);
参数$fac需要根据数据进行实验。
使用 $ fac = 2 你会得到想要的结果。
array (
0 => 0.0021030494216614,
1 => 0.0019940179461615,
2 => 0.0079320972662613,
3 => 0.0040485829959514,
4 => 0.0079320972662613,
5 => 0.0021030494216614,
6 => 0.0019940179461615,
7 => 0.0079320972662613,
8 => 0.0040485829959514,
9 => 0.0079320972662613,
10 => 0.0021030494216614,
)
如果 fac = 4,则包含值 0.015673981191223。
我在 PHP 中有这样一组数字:
$numbers = [
0.0021030494216614,
0.0019940179461615,
0.0079320972662613,
0.0040485829959514,
0.0079320972662613,
0.0021030494216614,
0.0019940179461615,
0.0079320972662613,
0.0040485829959514,
0.0079320972662613,
0.0021030494216614,
1.1002979145978,
85.230769230769,
6.5833333333333,
0.015673981191223
];
在 PHP 中,我试图找出这个数组中的离群值/异常值。
如您所见,异常是
1.1002979145978,
85.230769230769,
6.5833333333333,
0.015673981191223
我正在尝试查找并删除任何数组中的异常。
这是我的代码
function remove_anomalies($dataset, $magnitude = 1) {
$count = count($dataset);
$mean = array_sum($dataset) / $count;
$deviation = sqrt(array_sum(array_map("sd_square", $dataset, array_fill(0, $count, $mean))) / $count) * $magnitude;
return array_filter($dataset, function($x) use ($mean, $deviation) { return ($x <= $mean + $deviation && $x >= $mean - $deviation); });
}
function sd_square($x, $mean) {
return pow($x - $mean, 2);
}
但是,当我将 $numbers
数组放入其中时,当那里明显有更多异常值时,它只会给我 [85.230769230769]
作为异常值。
我试过摆弄 $magnitude
但没有任何改善。
此处显示的算法使用平均绝对偏差 (MAD) 一种可靠的度量来识别异常值。 所有距离超过MAD倍数的元素被连续移除,重新计算MAD。
function median(array $data)
{
if(($count = count($data)) < 1) return false;
sort($data, SORT_NUMERIC);
$mid = (int)($count/2);
if($count % 2) return $data[$mid];
return ($data[$mid] + $data[$mid-1])/2;
}
function mad(array $data)
{
if(($count = count($data)) < 1) return false;
$median = median($data);
$mad = 0.0;
foreach($data as $xi) {
$mad += abs($xi - $median);
}
return $mad/$count;
}
function cleanMedian(array &$data, $fac = 2.0)
{
do{
$unsetCount = 0;
$median = median($data);
$mad = mad($data) * $fac;
//remove all with diff > $mad
foreach($data as $idx => $val){
if(abs($val - $median) > $mad){
unset($data[$idx]);
++$unsetCount;
}
}
} while($unsetCount > 0);
}
使用方法:
$data = [
//..
];
cleanMedian($data);
参数$fac需要根据数据进行实验。 使用 $ fac = 2 你会得到想要的结果。
array (
0 => 0.0021030494216614,
1 => 0.0019940179461615,
2 => 0.0079320972662613,
3 => 0.0040485829959514,
4 => 0.0079320972662613,
5 => 0.0021030494216614,
6 => 0.0019940179461615,
7 => 0.0079320972662613,
8 => 0.0040485829959514,
9 => 0.0079320972662613,
10 => 0.0021030494216614,
)
如果 fac = 4,则包含值 0.015673981191223。