Слияние нескольких средних значений без вычисления итогов - PullRequest
0 голосов
/ 07 сентября 2018

В настоящее время у меня есть несколько пар [Average, Count] из сериализованных данных. Пользователь хочет иметь возможность объединять (группировать) несколько наборов значений и получать агрегированный результат.

Я, как легко, я просто сделаю Sum(Average * Count) / Sum(Count)

Но проблема в том, что некоторые значения очень велики, что вызывает арифметическое переполнение, если я суммирую их все.

Есть ли способ объединить среднюю часть без вычисления общей суммы? Подсчет части довольно очевиден.

Ответы [ 2 ]

0 голосов
/ 08 сентября 2018

Хотя ответ @jxh хорош и решает вашу проблему, его и ваш первоначальный подход делают два прохода по парам данных (сначала для общего количества, затем для среднего), что может снизить производительность. Вы можете сделать это за один проход, выполняя скользящее среднее. Его можно использовать, даже если пары приходят из потока, и вы не знаете, сколько их здесь

Некоторый код Python:

data = [(3.1, 12), (5.2, 17), (9.7, 11)]

total_count = 0
total_avg   = 0.0
for avg, count in data:
    n0 = total_count
    total_count += count

    p = float(n0) / float(total_count)
    total_avg = p*total_avg + (1.0 - p)*avg

print(total_count)
print(total_avg)
0 голосов
/ 07 сентября 2018

Предполагая, что Count и Average являются индексированными значениями, вы можете вычислить ваше совокупное среднее значение следующим образом:

TotalCount = Sum(Count)
TotalAverage = Sum(Average * (Count/TotalCount))

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

TotalCount = 0
TotalAverage = 0
for each index in data-set of [Average, Count]
    TotalCount = TotalCount + Count[index]
    Weight = Count[index]/TotalCount
    TotalAverage =   TotalAverage * (1 - Weight)
                   + Average[index] * Weight

Вы можете найти правильный подход, рассмотрев первые две пары.

Если была только первая пара:

TotalCount = Count[1]
TotalAverage = Average[1]

Но, если есть две пары:

TotalCount = Count[1] + Count[2]
TotalAverage =   Average[1] * (Count[1]/TotalCount) 
               + Average[2] * (Count[2]/TotalCount)

Если бы мы перебирали первую пару во вторую пару, то вычисление двух пар может выглядеть следующим образом:

TotalCount = TotalCount + Count[2]
TotalAverage =   TotalAverage * (TotalCount - Count[2])/TotalCount
               + Average[2]   * (Count[2]/TotalCount)

Если мы позволим Weight представлять Count[2]/TotalCount, вышеприведенное упрощается до:

TotalCount = TotalCount + Count[2]
Weight = Count[2]/TotalCount
TotalAverage =   TotalAverage * (1 - Weight)
               + Average[2] * Weight

Поскольку TotalCount и TotalAverage корректны на каждом шаге, который принимает новую пару сериализованных данных, [2] можно заменить итерационным индексом.

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