Có một lỗ hổng trong câu trả lời của Jason R, được thảo luận trong "Nghệ thuật lập trình máy tính" của Knuth. 2. Vấn đề xảy ra nếu bạn có độ lệch chuẩn là một phần nhỏ của giá trị trung bình: phép tính E (x ^ 2) - (E (x) ^ 2) bị nhạy cảm nghiêm trọng với các lỗi làm tròn điểm nổi.
Bạn thậm chí có thể tự thử điều này trong tập lệnh 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
Tôi nhận được -128.0 như một câu trả lời, rõ ràng là không có giá trị tính toán, vì toán học dự đoán rằng kết quả sẽ không âm.
Knuth trích dẫn một cách tiếp cận (tôi không nhớ tên của nhà phát minh) để tính toán giá trị trung bình và độ lệch chuẩn chạy theo cách tương tự:
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);
và sau mỗi bước, giá trị của giá trị m
trung bình và độ lệch chuẩn có thể được tính bằng sqrt(S/n)
hoặc sqrt(S/n-1)
tùy thuộc vào định nghĩa ưa thích của bạn về độ lệch chuẩn.
Phương trình tôi viết ở trên hơi khác so với phương trình trong Knuth, nhưng nó tương đương về mặt tính toán.
Khi tôi có thêm vài phút nữa, tôi sẽ viết mã công thức trên bằng Python và cho thấy rằng bạn sẽ nhận được câu trả lời không âm (hy vọng rằng nó gần với giá trị chính xác).
cập nhật: đây rồi.
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)
kết quả:
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}
Bạn sẽ lưu ý rằng vẫn còn một số lỗi làm tròn, nhưng nó không tệ, trong khi naive_stats
chỉ là lỗi.
chỉnh sửa: Chỉ cần chú ý bình luận của Belisarius trích dẫn Wikipedia có đề cập đến thuật toán Knuth.