J'essaie de trouver un moyen de calculer une moyenne cumulative mobile sans stocker le nombre et le total des données reçues jusqu'à présent.
J'ai proposé deux algorithmes, mais les deux doivent stocker le décompte:
- nouvelle moyenne = ((ancien décompte * anciennes données) + données suivantes) / prochain décompte
- nouvelle moyenne = ancienne moyenne + (données suivantes - ancienne moyenne) / prochain décompte
Le problème avec ces méthodes est que le nombre augmente de plus en plus, ce qui entraîne une perte de précision dans la moyenne résultante.
La première méthode utilise l'ancien décompte et le décompte suivant qui sont évidemment séparés de 1. Cela m'a fait penser qu'il existe peut-être un moyen de supprimer le décompte, mais malheureusement, je ne l'ai pas encore trouvé. Cela m'a fait un peu plus loin, ce qui a abouti à la deuxième méthode, mais le compte est toujours présent.
Est-ce possible, ou suis-je simplement à la recherche de l'impossible?
la source
Réponses:
Vous pouvez simplement faire:
Où
N
est le nombre d'échantillons sur lequel vous voulez faire la moyenne. Notez que cette approximation équivaut à une moyenne mobile exponentielle. Voir: Calculer la moyenne mobile / glissante en C ++la source
5
échantillons, la moyenne sera de 0,67.avg
initialisé à0
, vous vous retrouvez avec3.36
après 55
s, et4.46
après 10: cpp.sh/2ryql Pour les moyennes longues, c'est certainement une approximation utile.Cela suppose que le nombre n'a changé que d'une valeur. Dans le cas où il est modifié par des valeurs M alors:
C'est la formule mathématique (je crois la plus efficace), croyez que vous pouvez faire plus de code par vous-mêmes
la source
m
nouvelles valeurs sont prises en compte dans la nouvelle moyenne. Je crois qu'ilsum of new value
s'agit ici de la somme desm
nouvelles valeurs utilisées pour calculer la nouvelle moyenne.new_average = (old_average * (n-1) + new_value) / n
- Supprime l'un des clivages.À partir d' un blog sur l'exécution d'échantillons de calculs de variance, où la moyenne est également calculée à l'aide de la méthode de Welford :
Dommage que nous ne puissions pas télécharger d'images SVG.
la source
Voici encore une autre réponse offrant des commentaires sur la façon dont la réponse de Muis , Abdullah Al-Ageel et Flip est mathématiquement la même chose sauf écrite différemment.
Bien sûr, nous avons l' analyse de José Manuel Ramos expliquant comment les erreurs d'arrondi affectent chacune légèrement différemment, mais cela dépend de l'implémentation et changerait en fonction de la façon dont chaque réponse était appliquée au code.
Il y a cependant une assez grande différence
Il est dans Muis 's
N
, flip ' sk
, et Abdullah Al-Ageel den
. Abdullah Al-Ageel n'explique pas tout à fait ce quin
devrait être, maisN
etk
diffère en celaN
est " le nombre d'échantillons sur lesquels vous voulez faire la moyenne " tandis quek
le nombre de valeurs échantillonnées. (Bien que je doute deN
l' exactitude de l' appel du nombre d'échantillons .)Et nous arrivons ici à la réponse ci-dessous. C'est essentiellement la même vieille moyenne mobile pondérée exponentielle que les autres, donc si vous cherchez une alternative, arrêtez-vous ici.
Moyenne mobile pondérée exponentielle
Initialement:
Pour chaque valeur:
La différence est la
min(counter, FACTOR)
partie. C'est la même chose que de diremin(Flip's k, Muis's N)
.FACTOR
est une constante qui affecte la rapidité avec laquelle la moyenne «rattrape» la dernière tendance. Plus petit est le nombre, plus vite. (À1
ce n'est plus une moyenne et devient juste la dernière valeur.)Cette réponse nécessite le compteur en cours d'exécution
counter
. En cas de problème, lemin(counter, FACTOR)
peut être remplacé par justeFACTOR
, ce qui en fait la réponse de Muis . Le problème avec cela est que la moyenne mobile est affectée par tout ce quiaverage
est initialisé. S'il a été initialisé à0
, ce zéro peut prendre beaucoup de temps pour sortir de la moyenne.Comment ça finit par ressembler
la source
max(counter, FACTOR)
.min(counter, FACTOR)
retournera toujours FACTOR, non?min(counter, FACTOR)
est de tenir compte de la période d'échauffement. Sans cela, si votre FACTOR (ou N, ou le nombre d'échantillons souhaité) est de 1000, alors vous aurez besoin d'au moins 1000 échantillons avant d'obtenir un résultat précis, car toutes les mises à jour antérieures supposeront que vous avez 1000 échantillons, alors que vous ne pouvez avoir 20.La réponse de Flip est plus cohérente que celle de Muis.
En utilisant le format de nombre double, vous pouvez voir le problème d'arrondi dans l'approche Muis:
Lorsque vous divisez et soustrayez, un arrondi apparaît dans la valeur stockée précédente, la modifiant.
Cependant, l'approche Flip préserve la valeur stockée et réduit le nombre de divisions, réduisant ainsi l'arrondi et minimisant l'erreur propagée à la valeur stockée. L'ajout ne fera apparaître des arrondis que s'il y a quelque chose à ajouter (lorsque N est grand, il n'y a rien à ajouter)
Ces changements sont remarquables lorsque vous faites une moyenne de grandes valeurs tendant leur moyenne à zéro.
Je vous montre les résultats à l'aide d'un tableur:
Tout d'abord, les résultats obtenus:
Les colonnes A et B sont les valeurs n et X_n, respectivement.
La colonne C est l'approche Flip, et celle D est l'approche Muis, le résultat stocké dans la moyenne. La colonne E correspond à la valeur moyenne utilisée dans le calcul.
Un graphique montrant la moyenne des valeurs paires est le suivant:
Comme vous pouvez le voir, il existe de grandes différences entre les deux approches.
la source
Un exemple utilisant javascript, à titre de comparaison:
https://jsfiddle.net/drzaus/Lxsa4rpz/
Afficher l'extrait de code
la source
En Java8:
vous avez aussi
IntSummaryStatistics
,DoubleSummaryStatistics
...la source
Une solution Python soignée basée sur les réponses ci-dessus:
usage:
la source