Estou tentando encontrar uma maneira de calcular uma média cumulativa móvel sem armazenar a contagem e o total de dados recebidos até agora.
Eu vim com dois algoritmos, mas ambos precisam armazenar a contagem:
- nova média = ((contagem antiga * dados antigos) + próximos dados) / próxima contagem
- nova média = média antiga + (próximos dados - média antiga) / próxima contagem
O problema com esses métodos é que a contagem fica cada vez maior, resultando na perda de precisão na média resultante.
O primeiro método usa a contagem antiga e a próxima, que são obviamente 1 de diferença. Isso me fez pensar que talvez haja uma maneira de remover a contagem, mas infelizmente ainda não a encontrei. Isso me levou um pouco mais longe, resultando no segundo método, mas ainda assim a contagem está presente.
É possível ou estou apenas procurando o impossível?
moving-average
user1705674
fonte
fonte
Respostas:
Você pode simplesmente fazer:
Onde
N
está o número de amostras das quais você deseja calcular a média. Observe que esta aproximação é equivalente a uma média móvel exponencial. Veja: Calcular a média móvel / móvel em C ++fonte
5
amostras, a média será 0,67.avg
inicializado em0
, você acaba com3.36
após 55
s e4.46
após 10: cpp.sh/2ryql Para médias longas, esta é certamente uma aproximação útil.Isso pressupõe que a contagem mudou apenas em um valor. Caso seja alterado por valores M, então:
Esta é a fórmula matemática (acredito que seja a mais eficiente), acredite que você pode fazer mais códigos por conta própria
fonte
m
novos valores sendo fatorados na nova média. Eu acredito quesum of new value
aqui se destina a ser a soma dosm
novos valores usados para calcular a nova média.new_average = (old_average * (n-1) + new_value) / n
- Remove uma das divisões.De um blog sobre a execução de cálculos de variação de amostra, onde a média também é calculada usando o método de Welford :
Pena que não podemos fazer upload de imagens SVG.
fonte
Aqui está outra resposta que oferece comentários sobre como a resposta de Muis , Abdullah Al-Ageel e Flip são matematicamente a mesma coisa exceto que escritas de forma diferente.
Claro, temos José Manuel Ramos a análise de explicando como os erros de arredondamento afetam cada um de maneira ligeiramente diferente, mas isso depende da implementação e mudaria com base em como cada resposta foi aplicada ao código.
No entanto, há uma grande diferença
Está no Muis 's
N
, Flip 'sk
e Abdullah Al-Ageel 'sn
. Abdullah Al-Ageel não chega a explicar o quen
deveria ser, masN
ek
diferem em queN
é " o número de amostras em que deseja média ao longo ", enquantok
é a contagem de valores amostrados. (Embora eu tenha dúvidas se ligar paraN
o número de amostras é preciso.)E aqui chegamos à resposta abaixo. É essencialmente a mesma velha média móvel exponencial ponderada dos outros, então, se você estiver procurando por uma alternativa, pare aqui.
Média móvel exponencial ponderada
Inicialmente:
Para cada valor:
A diferença é a
min(counter, FACTOR)
parte. Isso é o mesmo que dizermin(Flip's k, Muis's N)
.FACTOR
é uma constante que afeta a rapidez com que a média "alcança" a tendência mais recente. Quanto menor o número, mais rápido. (Em1
não é mais uma média e apenas se torna o valor mais recente).Esta resposta requer o contador em execução
counter
. Se for problemático, omin(counter, FACTOR)
pode ser substituído por justFACTOR
, transformando-o na resposta de Muis . O problema em fazer isso é que a média móvel é afetada por tudo o queaverage
é inicializado. Se foi inicializado para0
, esse zero pode levar muito tempo para sair da média.Como fica parecendo
fonte
max(counter, FACTOR)
.min(counter, FACTOR)
sempre retornará FACTOR, certo?min(counter, FACTOR)
é dar conta do período de aquecimento. Sem ele, se seu FACTOR (ou N, ou contagem de amostra desejada) for 1000, você precisará de pelo menos 1000 amostras antes de obter um resultado preciso, já que todas as atualizações anteriores assumirão que você tem 1000 amostras, quando você pode apenas tem 20.A resposta de Flip é computacionalmente mais consistente do que a de Muis.
Usando o formato de número duplo, você pode ver o problema de arredondamento na abordagem de Muis:
Quando você divide e subtrai, um arredondamento aparece no valor armazenado anterior, alterando-o.
No entanto, a abordagem Flip preserva o valor armazenado e reduz o número de divisões, portanto, reduzindo o arredondamento e minimizando o erro propagado para o valor armazenado. Adicionar apenas trará arredondamentos se houver algo a adicionar (quando N é grande, não há nada a adicionar)
Essas mudanças são notáveis quando você faz com que uma média de valores grandes tenda a sua média para zero.
Eu mostro os resultados usando um programa de planilha:
Em primeiro lugar, os resultados obtidos:
As colunas A e B são os valores n e X_n, respectivamente.
A coluna C é a abordagem Flip, e a coluna D é a abordagem Muis, o resultado armazenado na média. A coluna E corresponde ao valor médio usado no cálculo.
Um gráfico que mostra a média dos valores pares é o próximo:
Como você pode ver, há grandes diferenças entre as duas abordagens.
fonte
Um exemplo usando javascript, para comparação:
https://jsfiddle.net/drzaus/Lxsa4rpz/
Exibir trecho de código
fonte
Em Java8:
você também tem
IntSummaryStatistics
,DoubleSummaryStatistics
...fonte
Uma solução Python bacana com base nas respostas acima:
uso:
fonte