Tengo una serie de números como este en 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 ];En PHP, estoy tratando de encontrar los valores atípicos/anomalías en esta matriz.
Como puede ver, las anomalías son
1.1002979145978, 85.230769230769, 6.5833333333333, 0.015673981191223Estoy tratando de encontrar y eliminar las anomalías en cualquier matriz.
Aquí está mi código
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); } Sin embargo, cuando introduzco mi matriz de $numbers , solo me da [85.230769230769] como valor atípico cuando claramente hay más valores atípicos allí. He intentado jugar con la $magnitude y eso no mejoró nada.
El algoritmo que se muestra aquí utiliza la desviación absoluta media (MAD), una medida robusta para identificar valores atípicos. Todos los elementos cuya distancia exceda un múltiplo de la MAD se eliminan continuamente y la MAD se vuelve a calcular.
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); }Cómo utilizar:
$data = [ //.. ]; cleanMedian($data);Se debe experimentar con el parámetro $fac dependiendo de los datos. Con el $fac = 2 se obtiene el resultado deseado.
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, )Con fac = 4 se incluye el valor 0.015673981191223.