Parece não haver função que simplesmente calcule a média móvel em numpy / scipy, levando a soluções complicadas .
Minha pergunta é dupla:
- Qual é a maneira mais fácil de (corretamente) implementar uma média móvel com numpy?
- Já que isso parece não trivial e sujeito a erros, há um bom motivo para não ter as baterias incluídas neste caso?
python
numpy
scipy
time-series
moving-average
goncalopp
fonte
fonte
Respostas:
Se você quer apenas um simples não ponderada média móvel, você pode facilmente implementá-lo com
np.cumsum
, quepode seré métodos mais rápido do que FFT base:EDIT Corrigido uma indexação errada por um ponto detectada por Bean no código. EDITAR
Portanto, acho que a resposta é: é realmente fácil de implementar e talvez o numpy já esteja um pouco inchado com funcionalidades especializadas.
fonte
ret[n:] -= ret[:-n]
NÃO é o mesmo queret[n:] = ret[n:] - ret[:-n]
. Corrigi o código nesta resposta. Edit: Não, alguém acabou de chegar antes de mim.A falta de uma função específica de domínio particular do NumPy talvez se deva à disciplina e fidelidade da equipe principal à diretiva principal do NumPy: fornecer um tipo de array N-dimensional , bem como funções para criar e indexar esses arrays. Como muitos objetivos básicos, este não é pequeno e o NumPy o faz de maneira brilhante.
O (muito) maior SciPy contém uma coleção muito maior de bibliotecas específicas de domínio (chamadas de subpacotes pelos desenvolvedores SciPy) - por exemplo, otimização numérica ( otimizar ), processamento de sinal ( sinal ) e cálculo integral ( integrar ).
Meu palpite é que a função que você está procurando está em pelo menos um dos subpacotes SciPy ( scipy.signal talvez); no entanto, eu procuraria primeiro na coleção de scikits SciPy , identificaria os scikits relevantes e procuraria a função de interesse lá.
Scikits são pacotes desenvolvidos de forma independente com base em NumPy / SciPy e direcionados a uma disciplina técnica específica (por exemplo, scikits-image , scikits-learn , etc.). Vários deles (em particular, o incrível OpenOpt para otimização numérica) eram altamente considerados, projetos maduros muito antes de escolher residir sob a rubrica scikits relativamente nova . A página inicial do Scikits gostou de listar cerca de 30 desses scikits , embora pelo menos vários deles não estejam mais em desenvolvimento ativo.
Seguir esse conselho o levaria à série scikits-time ; no entanto, esse pacote não está mais em desenvolvimento ativo; Na verdade, Pandas se tornou, AFAIK, a biblioteca de série temporal baseada em NumPy de fato .
O Pandas possui várias funções que podem ser usadas para calcular uma média móvel ; o mais simples deles é provavelmente rolling_mean , que você usa assim:
Agora, basta chamar a função rolling_mean passando no objeto Series e um tamanho de janela , que no meu exemplo abaixo é de 10 dias .
verifique se funcionou - por exemplo, valores comparados 10-15 na série original versus a nova série suavizada com média móvel
A função rolling_mean, junto com cerca de uma dúzia ou mais de outras funções, são agrupadas informalmente na documentação do Pandas sob a rubrica funções de janela móvel ; um segundo grupo relacionado de funções no Pandas é referido como funções exponencialmente ponderadas (por exemplo, ewma , que calcula a média ponderada exponencialmente móvel). O fato de que este segundo grupo não está incluído no primeiro ( funções de janela móvel ) é talvez porque as transformações exponencialmente ponderadas não dependem de uma janela de comprimento fixo
fonte
Uma maneira simples de conseguir isso é usando
np.convolve
. A ideia por trás disso é alavancar a forma como a convolução discreta é calculada e usá-la para retornar uma média móvel . Isso pode ser feito por convolução com uma sequência denp.ones
comprimento igual ao comprimento da janela deslizante que desejamos.Para fazer isso, podemos definir a seguinte função:
Esta função tomará a convolução da sequência
x
e uma sequência de unidades de comprimentow
. Observe que o escolhidomode
évalid
para que o produto da convolução seja dado apenas para pontos onde as sequências se sobrepõem completamente.Alguns exemplos:
Para uma média móvel com uma janela de comprimento
2
teríamos:E para uma janela de comprimento
4
:Como
convolve
funciona?Vamos dar uma olhada mais aprofundada na maneira como a convolução discreta está sendo calculada. A função a seguir tem como objetivo replicar a maneira como
np.convolve
está computando os valores de saída:Que, para o mesmo exemplo acima, também resultaria:
Portanto, o que está sendo feito em cada etapa é pegar o produto interno entre a matriz de uns e a janela atual . Nesse caso, a multiplicação por
np.ones(w)
é supérflua, visto que estamos tirando diretamente osum
da sequência.Abaixo está um exemplo de como as primeiras saídas são calculadas para que sejam um pouco mais claras. Vamos supor que queremos uma janela de
w=4
:E a seguinte saída seria calculada como:
E assim por diante, retornando uma média móvel da sequência depois que todas as sobreposições forem realizadas.
fonte
mode='valid'
pode ser substituído por'same'
. Apenas neste caso os pontos de borda gravitarão em torno de zero.Aqui estão uma variedade de maneiras de fazer isso, junto com alguns benchmarks. Os melhores métodos são versões que usam código otimizado de outras bibliotecas. O
bottleneck.move_mean
método provavelmente é o melhor. Ascipy.convolve
abordagem também é muito rápida, extensível e sintática e conceitualmente simples, mas não é escalonável para valores de janela muito grandes. Onumpy.cumsum
método é bom se você precisar de umanumpy
abordagem pura .Nota: Alguns destes (por exemplo
bottleneck.move_mean
) não são centralizados e irão deslocar seus dados.Tempo, janela pequena (n = 3)
Tempo, janela grande (n = 1001)
Memória, janela pequena (n = 3)
Memória, janela grande (n = 1001)
fonte
Esta resposta usando Pandas foi adaptada acima, pois
rolling_mean
não faz mais parte do PandasAgora, basta chamar a função
rolling
no dataframe com um tamanho de janela, que no meu exemplo abaixo é de 10 dias.fonte
Acho que isso pode ser facilmente resolvido usando o gargalo
Veja o exemplo básico abaixo:
Isso dá a média de movimento ao longo de cada eixo.
"mm" é a média móvel para "a".
"janela" é o número máximo de entradas a considerar para a média móvel.
"min_count" é o número mínimo de entradas a considerar para a média móvel (por exemplo, para o primeiro elemento ou se a matriz tiver valores nan).
A parte boa é que o gargalo ajuda a lidar com os valores nan e também é muito eficiente.
fonte
No caso de você querer cuidar das condições de borda com cuidado ( calcular a média apenas dos elementos disponíveis nas bordas ), a função a seguir fará o truque.
fonte
Experimente este pedaço de código. Acho que é mais simples e faz o trabalho. lookback é a janela da média móvel.
No
Data[i-lookback:i, 0].sum()
coloquei0
para me referir à primeira coluna do conjunto de dados, mas você pode colocar qualquer coluna que desejar, caso tenha mais de uma coluna.fonte
Na verdade, eu queria um comportamento ligeiramente diferente da resposta aceita. Eu estava construindo um extrator de recurso de média móvel para um
sklearn
pipeline, então exigi que a saída da média móvel tivesse a mesma dimensão da entrada. O que eu quero é que a média móvel assuma que a série permanece constante, ou seja, uma média móvel de[1,2,3,4,5]
com a janela 2 daria[1.5,2.5,3.5,4.5,5.0]
.Para vetores de coluna (meu caso de uso), obtemos
E para matrizes
Obviamente, não é necessário assumir valores constantes para o preenchimento, mas isso deve ser adequado na maioria dos casos.
fonte
talib contém uma ferramenta de média móvel simples, bem como outras ferramentas de cálculo de média semelhantes (ou seja, média móvel exponencial). Abaixo, compara o método com algumas das outras soluções.
Uma ressalva é que o real deve ter elementos de
dtype = float
. Caso contrário, o seguinte erro é geradofonte
Aqui está uma implementação rápida usando numba (lembre-se dos tipos). Observe que ele contém nans onde alterado.
fonte
fonte
Eu uso a solução da resposta aceita , ligeiramente modificada para ter o mesmo comprimento de saída como entrada, ou
pandas
a versão mencionada em um comentário de outra resposta. Resumo ambos aqui com um exemplo reproduzível para referência futura:fonte
Ao comparar a solução abaixo com aquela que usa cumsum de numpy, essa leva quase metade do tempo . Isso ocorre porque não é necessário percorrer todo o array para fazer o cumsum e depois fazer toda a subtração. Além disso, o cumsum pode ser " perigoso " se a matriz for enorme e o número for enorme ( possível estouro ). Claro, também aqui o perigo existe, mas pelo menos são somados apenas os números essenciais.
fonte