Hay una falla en la respuesta de Jason R, que se discute en el vol. "Arte de la programación de computadoras" de Knuth. 2. El problema surge si tiene una desviación estándar que es una pequeña fracción de la media: el cálculo de E (x ^ 2) - (E (x) ^ 2) sufre de una severa sensibilidad a los errores de redondeo de coma flotante.
Incluso puedes probar esto tú mismo en un script de 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
Obtengo -128.0 como respuesta, lo que claramente no es computacionalmente válido, ya que las matemáticas predicen que el resultado no debería ser negativo.
Knuth cita un enfoque (no recuerdo el nombre del inventor) para calcular la media de carrera y la desviación estándar que es algo así:
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);
y luego, después de cada paso, el valor de m
es la media, y la desviación estándar se puede calcular como sqrt(S/n)
o sqrt(S/n-1)
según cuál sea su definición favorita de desviación estándar.
La ecuación que escribo arriba es ligeramente diferente a la de Knuth, pero es computacionalmente equivalente.
Cuando tenga unos minutos más, codificaré la fórmula anterior en Python y mostraré que obtendrás una respuesta no negativa (que con suerte está cerca del valor correcto).
actualización: aquí está.
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)
resultado:
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}
Notarás que todavía hay algún error de redondeo, pero no está mal, mientras que naive_stats
solo vomita.
editar: Acabo de notar el comentario de Belisario citando Wikipedia que menciona el algoritmo de Knuth.