У відповіді Джейсона Р є недолік, який обговорюється у "Кмітці комп’ютерного програмування" Кнута. 2. Проблема виникає, якщо у вас є стандартне відхилення, яке є невеликою часткою середнього: обчислення E (x ^ 2) - (E (x) ^ 2) страждає від сильної чутливості до помилок округлення плаваючої точки.
Ви навіть можете спробувати це самостійно в сценарії Python:
ofs = 1e9
A = [ofs+x for x in [1,-1,2,3,0,4.02,5]]
A2 = [x*x for x in A]
(sum(A2)/len(A))-(sum(A)/len(A))**2
Я отримую -128.0 як відповідь, яка явно не обчислювально обгрунтована, оскільки математика передбачає, що результат повинен бути негативним.
Кнут наводить підхід (я не пам’ятаю прізвища винахідника) для обчислення середньої тривалості та середнього відхилення, яка має щось подібне:
initialize:
m = 0;
S = 0;
n = 0;
for each incoming sample x:
prev_mean = m;
n = n + 1;
m = m + (x-m)/n;
S = S + (x-m)*(x-prev_mean);
а потім після кожного кроку значення m
середнього значення є, а стандартне відхилення можна обчислити як sqrt(S/n)
або sqrt(S/n-1)
залежно від того, яке ваше улюблене визначення стандартного відхилення.
Рівняння, про яке я пишу вище, трохи відрізняється від рівня в Кнуті, але воно обчислювально рівнозначне.
Коли у мене ще кілька хвилин, я зашифрую вищевказану формулу в Python і покажу, що ви отримаєте негативну відповідь (це, сподіваємось, близьке до правильного значення).
оновлення: ось воно.
test1.py:
import math
def stats(x):
n = 0
S = 0.0
m = 0.0
for x_i in x:
n = n + 1
m_prev = m
m = m + (x_i - m) / n
S = S + (x_i - m) * (x_i - m_prev)
return {'mean': m, 'variance': S/n}
def naive_stats(x):
S1 = sum(x)
n = len(x)
S2 = sum([x_i**2 for x_i in x])
return {'mean': S1/n, 'variance': (S2/n - (S1/n)**2) }
x1 = [1,-1,2,3,0,4.02,5]
x2 = [x+1e9 for x in x1]
print "naive_stats:"
print naive_stats(x1)
print naive_stats(x2)
print "stats:"
print stats(x1)
print stats(x2)
результат:
naive_stats:
{'variance': 4.0114775510204073, 'mean': 2.0028571428571427}
{'variance': -128.0, 'mean': 1000000002.0028572}
stats:
{'variance': 4.0114775510204073, 'mean': 2.0028571428571431}
{'variance': 4.0114775868357446, 'mean': 1000000002.0028571}
Ви зауважите, що все-таки є якась помилка округлення, але це непогано, тоді як naive_stats
просто тягне.
редагувати: Щойно помітив коментар Велізарія з посиланням на Вікіпедію, де йдеться про алгоритм Кнута.