计算平均值而不被线性抛出

时间:2010-10-19 19:16:35

标签: php algorithm average

我试图计算一个平均值,而不是被一小组远距离数字(即1,2,1,2,3,4,50)抛弃,单个50将甩掉整个平均值。

如果我有这样的数字列表:

  

19,20,21,21,22,30,60,60

平均值 31

中位数 30

模式是21& 60(平均 40.5

但是任何人都可以看到大部分都在19-22(5英寸,3英寸)的范围内,如果你得到的只是主要范围的平均值,那么 20.6 (差异很大)以上数字)

我在想你可以这样:

  

C + d-R

c是数字的计数,d是不同的值,r是范围。然后你可以将它应用于所有可能的范围,最高分是获得平均值的最佳范围。

例如19,20,21,21,22将是5个数字,4个不同的值,范围是3(22 - 19)。如果你把它插入我的方程式,你得到5 + 4-3 = 6

如果您将此应用于整个数字列表,则为8 + 6-41 = -27

我认为这非常好用,但我必须创建一个巨大的循环来测试所有可能的范围。在我的小例子中,有21个可能的范围:

  

19-19,19-20,19-21,19-22,19-30,19-60,20-20,20-21,20-22,20-30,20-60,21-21 ,21-22,21-30,21-60,22-22,22-30,22-60,30-30,30-60,60-60

我想知道是否有更有效的方式来获得这样的平均值。

或者如果有人一起拥有更好的算法?

5 个答案:

答案 0 :(得分:2)

这里可能会使用standard deviation,这基本上可以衡量数据点的集中程度。您可以将异常值定义为超出平均值的任何超过1个标准差(或任何其他适合您的数字),将它们抛出,并计算出不包含它们的新平均值。

答案 1 :(得分:2)

这是一个非常天真的实现,您可以根据自己的需要进行修复。我故意保持它非常冗长。它基于通常用于解决这些问题的五个数字摘要。

function get_median($arr) {
    sort($arr);
    $c = count($arr) - 1;
    if ($c%2) {
        $b = round($c/2);
        $a = $b-1;
        return ($arr[$b] + $arr[$a]) / 2 ;
    } else {
        return $arr[($c/2)];
    }
}

function get_five_number_summary($arr) {
    sort($arr);
    $c = count($arr) - 1;
    $fns = array();
    if ($c%2) {
        $b = round($c/2);
        $a = $b-1;
        $lower_quartile = array_slice($arr, 1, $a-1);
        $upper_quartile = array_slice($arr, $b+1, count($lower_quartile));
        $fns = array($arr[0], get_median($lower_quartile), get_median($arr), get_median($upper_quartile), $arr[$c-1]);
        return $fns;
    }
    else {
        $b = round($c/2);
        $a = $b-1;
        $lower_quartile = array_slice($arr, 1, $a);
        $upper_quartile = array_slice($arr, $b+1, count($lower_quartile));
        $fns = array($arr[0], get_median($lower_quartile), get_median($arr), get_median($upper_quartile), $arr[$c-1]);
        return $fns;
    }
}

function find_outliers($arr) {
    $fns = get_five_number_summary($arr);
    $interquartile_range = $fns[3] - $fns[1];
    $low = $fns[1] - $interquartile_range;
    $high = $fns[3] + $interquartile_range;
    foreach ($arr as $v) {
        if ($v > $high || $v < $low)
            echo "$v is an outlier<br>";
    }
}

//$numbers = array( 19,20,21,21,22,30,60 ); // 60 is an outlier
$numbers = array( 1,230,239,331,340,800); // 1 is an outlier, 800 is an outlier
find_outliers($numbers);

请注意,此方法虽然比标准偏差更容易实现,但会在您的示例中找到两个60个异常值,但它的效果非常好。请使用代码,希望它有用!

要了解该算法的工作原理以及我如何实施该算法,请转到:http://www.mathwords.com/o/outlier.htm

当然,这并不是计算最终平均值,但是在你运行find_outliers()之后它是微不足道的:P

答案 2 :(得分:1)

为什么不使用中位数?它不是30,它是21.5。

答案 3 :(得分:0)

您可以将值放入数组中,对数组进行排序,然后找到median,这通常是比平均值更好的数字,因为它会自动对异常值进行折扣,使得它们不会比其他任何值更重要数。

答案 4 :(得分:0)

您可以对数字进行排序,选择您喜欢的子范围(例如,中间的90%),并取其平均值。

你的问题没有一个真正的答案,因为总会有分布会给你一个有趣的答案(例如,考虑有偏见的双模态分布)。这就是为什么统计数据通常可以使用显示均值,中位数,四分位数和异常值的盒须图来表示。