LINUX.ORG.RU

среднеквадратичное отклонение


1

2

Есть код, написанный на Javascript ( впрочем неважно на чем написан). Задачка след: есть хэш данных, нужно выкинуть те данные, которые «выбиваются» из общего ряда. Алгоритм взят в википедии. Только вот почему-то он не работает. То ли ошибка в коде, то ли в википедии. Нужно чтобы выбивалось значение 200000, чего не происходит ( отдается весь хэш).

function Test() {
    this.data = { 'a' : 0, 'b' : 6, 'c' : 8, 'd' : 14, 'e' : 11, 'f' : 200, 'aa' : 201, 'www' : 200000 }
}

Test.prototype = {
    StandardDeviation: function (sa) {
        var n = 0;
        var sum = 0;
        for (var key in this.data) {
            n = n + 1;
            sum = sum + Math.pow(( this.data[key] - sa ), 2)
        }
        if (n > 0) {
            return Math.sqrt(sum / n)
        } else {
            return 0
        }
    },
    SimpleAverage: function () {
        var n = 0;
        var sum = 0;
        for (var key in this.data) {
            n = n + 1;
            sum = sum + this.data[key]
        }

        if (n > 0) {
            return sum / n
        } else {
            return 0
        }
    },
    Middle: function (sd, sa) {
        var hash = {};
        for (var key in this.data) {
            if ( this.data[key] <= 3 * sd + sa  && this.data[key] >= sa - 3 * sd )  {
                hash[key] = this.data[key]
            }
        }
        return hash
    },
    run: function () {
        var sa = this.SimpleAverage();
        var sd = this.StandardDeviation(sa);
        console.log(this.Middle(sd, sa));
    }

};

exports.Test = Test;

r = new Test()
r.run()
★★☆☆

var n = 0; ... n = n + 1; ... if (n > 1)

anonymous ()

если очепяток нет, то всё хорошо должно быть:

avg :: [Double] -> Double
avg xs = s / l
  where
    s = sum xs
    l = fromIntegral $ length xs

dva :: [Double] -> Double
dva xs = (sqrt s)/n
  where
    n = fromIntegral $ length xs - 1
    s = sum $ map (^2) xs

inDVA :: Double -> Double -> Double -> Double -> Bool
inDVA s d n x = (x < (s+d*n)) && (x > (s-d*n))

filterDVA :: [a] -> (a -> Double) -> [a]
filterDVA xs convert = filter (not . inDVA' . convert) xs
   where
    cxs = map convert xs
    inDVA' = inDVA (avg cxs) (dva cxs) 3


test_data :: [(Char,Double)]
test_data = [('a',0),('b', 6),('c', 8),('d',14),('e',11),('f',200),('!', 201), ('?',  200000)]

test = filterDVA test_data snd

запуск

λ> test
[('?',200000.0)]

qnikst ★★★★★ ()
Ответ на: комментарий от anonymous

Есть код, написанный на Javascript ( впрочем неважно на чем написан).

..

qnikst ★★★★★ ()
Ответ на: комментарий от qnikst

Это как в старом анекдоте, когда человеку, который занимается самолечением по учебникам, предрекают смерть от очепатки.

dave ★★★★★ ()
Ответ на: комментарий от SI

гм дейсвтителтно, заменил Math.sqrt(sum / n) на Math.sqrt(sum) / n - все стало работаь. Очепятка в википедии ?

нет, это не опечатка, n должно быть под корнем. Это легко проверяется на очереди из двух значений -1, +1 в одинаковом кол-ве, ср.кв. отклонение не должно зависеть от длины и всегда равно 1.

Просто у тебя в выборке слишком мало значений, т.е. 200к не выходит за три сигмы.

mashina ★★★★★ ()
Последнее исправление: mashina (всего исправлений: 1)
Ответ на: комментарий от qnikst

действительно опечатка в вики

В википедии всё правильно написано.

yvv ★★☆ ()

Среднеквадратичное отклонение считается как корень из (средний квадрата минус квадрат среднего). Ваш К.О.

AIv ★★★★★ ()

У меня почему то по правилу трех сигм отфильтровать не получилось

<?php
$a = array("a" => 10, "b" => 6, "c" => 8, "d" => 14, "e" => 11, "f" => 200, "aa" => 201, "www" => 200000);
$n = count($a);
$s = array_sum($a);
$m = $s / $n;
$r = 0;
foreach ($a as $i)
    $r = $r + pow(($i - $m), 2);
$o = sqrt($r / $n);
foreach ($a as $v => $i) {
    if (!($i <= $m + (2 * $o) and ( $m + (2 * $o)))) {
        echo "\$a[$v] => $i.\n" . PHP_EOL;        
    }
}
?>

результат

$a[www] => 200000

где косяк?

anonymous ()

признаюсь, я идиот и всё забыл :)

qnikst ★★★★★ ()
Ответ на: комментарий от mashina
N = 8
from numpy import  mean, var, std
x=[0,6,8,14,11,200,201,200000]
xm = mean(x)
xv = var(x)  
xs = std(x)  
for item in x:
    if not(item <= xm+(2*xs) and item >= xm-(2*xs)) :
        print item

результат

200000

Один фиг не получается по правилу трех сигм( что не так?

anonymous ()
Ответ на: комментарий от anonymous

Просто у тебя в выборке слишком мало значений, т.е. 200к не выходит за три сигмы.

Gotcha!

anonymous ()
Ответ на: комментарий от mashina

а почему не указано кол-во значений на которых это работает в условиях применения этого метода ?

SI ★★☆☆ ()
Ответ на: комментарий от mashina

да пропустил там кое что) но я не пыхер

anonymous ()

Учебное пособие по предмету: Методы и средства обработки сигналов

Необходимо подчеркнуть, что само значение σ можно получить лишь при значительном числе наблюдательных данных, во всяком случае больше десяти. Реально вместо σ имеем среднеквадратическую ошибку ε, которая сама вычисляется с ошибкой. В этом случае критерий трех сигм нужно применять с большой осторожностью. При малом числе наблюдательных данных, или, как говорят, в случае малой выборки, описанная методика интервального оценивания становится несостоятельной. Нормальный закон распределения необходимо заменить на распределение Стьюдента.

anonymous ()

1) «правило трех сигм» работает только когда у тебя выполняется закон нормального распределения.

2) у тебя может просто быть многомодальное распределение и какую из мод выкидывать никакой алгоритм за человека не решит. возможно только решение задачи о разделении смеси распределений.

anonymous ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.