Estoy tratando de encontrar una manera de calcular un promedio acumulativo móvil sin almacenar el recuento y los datos totales que se reciben hasta ahora.
Se me ocurrieron dos algoritmos, pero ambos necesitan almacenar el recuento:
- nuevo promedio = ((recuento antiguo * datos antiguos) + siguiente dato) / siguiente recuento
- nuevo promedio = promedio anterior + (datos siguientes - promedio anterior) / siguiente recuento
El problema con estos métodos es que el recuento aumenta cada vez más, lo que resulta en una pérdida de precisión en el promedio resultante.
El primer método utiliza el recuento anterior y el siguiente, que obviamente están separados por 1. Esto me hizo pensar que tal vez haya una forma de eliminar el recuento, pero desafortunadamente aún no lo he encontrado. Sin embargo, me llevó un poco más lejos, lo que resultó en el segundo método, pero aún está presente el recuento.
¿Es posible o solo estoy buscando lo imposible?
fuente
Respuestas:
Simplemente puede hacer:
¿Dónde
N
está el número de muestras sobre las que desea promediar? Tenga en cuenta que esta aproximación es equivalente a una media móvil exponencial. Ver: Calcular promedio móvil / móvil en C ++fuente
5
muestras, el promedio será 0.67.avg
inicializado en0
, termina3.36
después de 55
s, y4.46
después de 10: cpp.sh/2ryql Para promedios largos, esta es sin duda una aproximación útil.Esto es asumiendo que el recuento solo cambió en un valor. En caso de que sea cambiado por valores M, entonces:
Esta es la fórmula matemática (creo que la más eficiente), creo que pueden hacer más código por ustedes mismos
fuente
m
nuevos valores en el nuevo promedio. Creo quesum of new value
aquí se pretende que sea la suma de losm
nuevos valores que se utilizan para calcular el nuevo promedio.new_average = (old_average * (n-1) + new_value) / n
- Elimina una de las divisiones.De un blog sobre la ejecución de cálculos de varianza de muestra, donde la media también se calcula utilizando el método de Welford :
Lástima que no podamos subir imágenes SVG.
fuente
Aquí hay otra respuesta que ofrece un comentario sobre cómo las respuestas de Muis , Abdullah Al-Ageel y Flip son matemáticamente iguales, excepto que están escritas de manera diferente.
Claro, tenemos el análisis de José Manuel Ramos que explica cómo los errores de redondeo afectan a cada uno de manera ligeramente diferente, pero eso depende de la implementación y cambiaría según la forma en que cada respuesta se aplique al código.
Sin embargo, hay una diferencia bastante grande
Está en Muis 's
N
, flip ' sk
, y Abdullah Al-Ageel 'sn
. Abdullah Al-Ageel no explica lo quen
debería ser, peroN
yk
se diferencian en queN
es " el número de muestras en las que desee promedio a lo largo ", mientras quek
es el recuento de los valores muestreados. (Aunque tengo dudas sobre si llamarN
al número de muestras es exacto).Y aquí llegamos a la respuesta a continuación. Es esencialmente el mismo promedio móvil ponderado exponencial de edad que los demás, así que si estaba buscando una alternativa, deténgase aquí.
Media móvil ponderada exponencial
Inicialmente:
Por cada valor:
La diferencia es la
min(counter, FACTOR)
parte. Esto es lo mismo que decirmin(Flip's k, Muis's N)
.FACTOR
es una constante que afecta la rapidez con que el promedio "se pone al día" con la última tendencia. Cuanto menor sea el número, más rápido. (1
Ya no es un promedio y simplemente se convierte en el último valor).Esta respuesta requiere el contador corriente
counter
. Si es problemático,min(counter, FACTOR)
se puede reemplazar con soloFACTOR
, convirtiéndolo en la respuesta de Muis . El problema de hacer esto es que la media móvil se ve afectada por lo queaverage
se inicialice. Si se inicializó en0
, ese cero puede tardar mucho en salir del promedio.Como termina luciendo
fuente
max(counter, FACTOR)
.min(counter, FACTOR)
siempre devolverá FACTOR, ¿verdad?min(counter, FACTOR)
es tener en cuenta el período de calentamiento. Sin él, si su FACTOR (o N, o el recuento de muestras deseado) es 1000, entonces necesitará al menos 1000 muestras antes de obtener un resultado preciso, ya que todas las actualizaciones anteriores supondrán que tiene 1000 muestras, cuando solo puede tienen 20.La respuesta de Flip es computacionalmente más consistente que la de Muis.
Usando el formato de doble número, podría ver el problema de redondeo en el enfoque de Muis:
Cuando divide y resta, aparece un redondeo en el valor almacenado anterior y lo cambia.
Sin embargo, el enfoque Flip conserva el valor almacenado y reduce el número de divisiones, por lo tanto, reduce el redondeo y minimiza el error propagado al valor almacenado. Agregar solo traerá redondeos si hay algo que agregar (cuando N es grande, no hay nada que agregar)
Esos cambios son notables cuando haces que una media de valores grandes tiende a cero.
Te muestro los resultados usando un programa de hoja de cálculo:
En primer lugar, los resultados obtenidos:
Las columnas A y B son los valores n y X_n, respectivamente.
La columna C es el enfoque Flip y la D es el enfoque Muis, el resultado almacenado en la media. La columna E corresponde con el valor medio utilizado en el cálculo.
Un gráfico que muestra la media de valores pares es el siguiente:
Como puede ver, existen grandes diferencias entre ambos enfoques.
fuente
Un ejemplo usando javascript, a modo de comparación:
https://jsfiddle.net/drzaus/Lxsa4rpz/
Mostrar fragmento de código
fuente
En Java8:
también tienes
IntSummaryStatistics
,DoubleSummaryStatistics
...fuente
Una solución de Python ordenada basada en las respuestas anteriores:
uso:
fuente