рассчитать среднее значение и дисперсию за одну итерацию - PullRequest
15 голосов
/ 26 февраля 2010

У меня есть итератор чисел, например, объект файла:

f = open("datafile.dat")

Теперь я хочу вычислить:

mean = get_mean(f)
sigma = get_sigma(f, mean)

Какая реализация лучше? Предположим, что файл большой, и я хотел бы не читать его дважды.

Ответы [ 8 ]

12 голосов
/ 26 февраля 2010

Если вы хотите выполнить итерацию один раз, вы можете написать свою функцию суммы:

def mysum(l):
    s2 = 0
    s = 0
    for e in l:
        s += e
        s2 += e * e
    return (s, s2)

и используйте результат в функции sigma.

Редактировать : теперь вы можете рассчитать дисперсию следующим образом: (s2 - (s * s) / N) / N

Принимая во внимание комментарий @ Adam Bowen,
имейте в виду, что если мы используем математические трюки и преобразуем исходные формулы
мы можем ухудшить результаты.

5 голосов
/ 26 февраля 2010

Я думаю, что у Ника Д. правильный ответ.

Предполагая, что вы хотите вычислить как среднее значение, так и дисперсию за один цикл файла (и вам не нужны две функции, которые должны вызываться одна за другой), вы можете собрать сумму значений и их квадраты и их используют такие суммы (вместе с количеством считываемых элементов) для вычисления одновременно среднего и дисперсии.

Есть некоторые проблемы со стабильностью чисел, но идея в

http://en.wikipedia.org/wiki/Computational_formula_for_the_variance

- это основной ингредиент, который вам нужен. Некоторые подробности на

http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance

где я предлагаю вам прочитать «Наивный алгоритм».

Надеюсь, это поможет,

Massimo

2 голосов
/ 09 февраля 2012

Вы можете вычислить оба за один проход. См:

http://www.johndcook.com/standard_deviation.html

2 голосов
/ 26 февраля 2010

Составьте список из итерируемого или используйте itertools.tee().

1 голос
/ 26 февраля 2010

Поскольку я чувствую, что в нескольких ответах разбросаны хорошие элементы, я хотел бы резюмировать:

  • Если ваш файл слишком велик, чтобы удобно помещаться в памяти, и если вы хотитехорошая точность в дисперсии, вам нужно прочитать файл дважды (с одним проходом дисперсия - это разница между двумя большими числами, которая не является точной из-за ограничений с плавающей запятой).Обратите внимание, что ваша операционная система, скорее всего, обеспечит некоторое автоматическое ускорение для чтения второго файла, поскольку она может все еще находиться в ОЗУ во время второго прохода.

  • Если вам все равноТочность отклонения, вы можете просто перебрать один раз по файлу и вычислить величины, предложенные Ником Д., с подробностями, предоставленными в комментарии Адамом Боуэном.

1 голос
/ 26 февраля 2010

Я не уверен, что есть большой выбор.

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

Если у вас достаточно памяти, вы можете получить доступ к вводу / выводу, загрузив ваш файл в память во время первой итерации, но это все IMO.

0 голосов
/ 22 августа 2012

Вы можете элегантно использовать уменьшение карты

образец - список, который вы хотите получить его дисперсию

образец = [a, b, c, ...]

mean = float(reduce(lambda x,y : x+y, sample)) / len(sample)

variance = reduce(lambda x,y: x+y, map(lambda xi: (xi-mean)**2, sample))/ len(sample)

В краткой строке кода:

variance = reduce(lambda x,y: x+y, map(lambda xi: (xi-(float(reduce(lambda x,y : x+y, sample)) / len(sample)))**2, sample))/ len(sample)
0 голосов
/ 26 февраля 2010

У вас есть два решения

  1. Составьте список из вашего итератора и зацикливайте его столько раз, сколько пожелаете. Недостатком является то, что все будет в памяти, поэтому не подходит, если ваш файл большой. Простое использование itertools.tee также не спасет вас

  2. Нет другого решения, , если только , вам не нужно передавать выходные данные get_mean в get_sigma, потому что в этом случае они могут быть только последовательно, но если вы удалите это ограничение, то вы можете запускать обе функции параллельно, используя потоки, и использовать itertools.tee, чтобы иметь два итератора из одного

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...