Ao longo dos meus estudos de analise de dados, previsões, Machine Learning, Deep Learning e estatísticas eu percebi uma complexidade maior no entendimento sobre séries temporais, seja pela grande necessidade de entender uma série de outros conceitos que não estão relacionados aos modelos de previsão numérica e classificação, seja pela falta de material em português com uma abordagem bem teórica sobre séries temporais e seus modelos de forecasting. Portanto neste artigo eu busco abordar uma sequencia de conceitos básicos sobre séries temporais que ajudam não só a entender melhor os gráficos do seus dados como também a entender como aplicar algumas formulas e funções para transformar o seus dados em algo mais legível e preparado para determinados modelos de Machine Learning.
Recursos utilizados.
- Visual code com extensão do jupyter.
- Python 3.7.4
- Conda enviroment
- Pacotes: Pandas, Matplotlib, Numpy, PMDARIMA, Plotly, Statsmodels.
O que é uma série?
Uma serie nada mais é do que uma matriz unidimensional, onde geralmente temos um índice único para o conjunto de dados e cada coluna do nosso conjunto + índice se torna uma série. Em séries temporais seguimos este mesmo conceito, no entanto nosso indice deve ser um valor referente ao tempo.
Decomposição de uma série temporal:
O processo de decomposição de uma série temporal se trata em abstrair de um determinado conjunto de dados, diversos aspectos sobre o mesmo. Em séries temporais a decomposição pode se dividir em 3 subconjuntos: Tendencia, sazonalidade e ruido (sobra, componente aleatório). Na biblioteca statsmodel é possível obter uma decomposição facilmente:
Séries estacionarias:
Uma série estacionaria são série que não possui uma tendencia, ou seja, não possuem um crescimento ou decréscimo, elas não tem também grande variância na media ao longo do seu período. Portanto é considerado uma série estacionaria aquela série que em certos períodos possui a mesma média. A série estacionaria é importante por que existe algumas técnicas analíticas que precisam ser de séries estacionarias, desta forma se houver uma série que não é estacionaria pode se aplicar alguma transformação para tornar estacionaria.
Algumas técnicas como Dickey-Fuller, KPSS e Philips-Perron são utilizadas para identificar se determinada série é estacionaria. É possível também aplicar funções logarítmica para transformar os dados e gerar um resultado com uma maior suavização tornando os dados mais estacionários. Por fim pode-se aplicar também a técnica de diferenciação para deixar uma série estacionaria, que consiste em obter pequenos períodos da sua população ou amostra e aplicar a diferença entre eles tornando os dados mais próximos.
Para diferenciação, basta utilizar a função diff do pacote Numpy sobre os valores da sua série:
É possível também aplicar a diferenciação com a função Log do Numpy para tornar os dados um pouco mais estacionários. Já as técnicas mencionadas anteriormente referente a identificação de se determinada série temporal é estacionaria ou não, existe ambas no pacote statsmodel, por exemplo o teste de Dickey-Fuller pode ser feito com apenas uma linha:
onde aqui ele ira retornar alguns dados sobre o que foi identificado entre eles o Valor de P que é a porcentagem de quanto aquele conjunto é estacionário ou não, geralmente é considerar um P-VALUE abaixo de 0.05 como um bom resultado para o objetivo da métrica.
O intuito deste artigo não se aprofundar nestas técnicas, mas é possível encontrar vários materiais sobre ambas as técnicas.
Séries Sazonais:
No processo de decomposição de uma série temporal podemos encontrar uma parte dos dados que possuem um comportamento com grande variação mas que segue um padrão, ou seja, uma amostra dos dados que possui oscilação mas que essa oscilação se repete ao longo dos dados.
Séries com tendencia:
Uma série com tendencia como o proprio nome sugere, se trata de uma parte ou não da série temporal que possui um crescimento ou um decrescimento único e constante, quando esse crescimento ou decrescimento é ainda maior, chamamos de tendencia exponencial. Para tendencia temos também algumas técnicas para identificar o quanto determinado conjunto de dados é uma tendencia ou não, são eles o teste de Wald, Cox-Stuart, Mann-Kendall.
Ruido de uma série:
O ruido ou resíduo é basicamente o que sobra de uma série temporal quando retiramos todos os aspectos listados acima, ou seja, tendencia e sazonalidade, em outras palavras o ruido é uma parte aleatória não correlacionada do conjunto de dados.
Médias móveis em séries temporais:
Médias móveis aplicado em séries temporais se trata de um processo de transformação dos dados que tem como objetivo transformar os dados para uma série mais simples sem muitas variações, isso ajuda a identificar tendencias bem como retirar outliers (Valores discrepantes dentro da media dos dados):
A aplicação de médias moveis é basicamente o calculo da média em pequenos períodos do seu conjunto de dados, o que no Pandas chamamos de Windows (Janelas de intervalo). No pandas um exemplo de função de média móvel é pd.rolling_mean onde você informa seu conjunto de dados e a janela de intervalo, existe muitas outras técnicas:
- Média Ponderada.
- Média diferencial.
Até este ponto do artigo o objetivo foi passar uma visão do mundo que envolve trabalhar com um dataframe de um índice temporal com 1 coluna. Agora vamos para um modelo de forecast poderoso e muito utilizado.
Utilizando o pacote PMDARIMA (Autoarima)
O pacote pmdarima é utilizado para aplicar uma especie de força bruta em um modelo arima testando diversos parâmetros afim de encontrar o melhor cenário com baixo AIC. No entanto antes de começarmos vamos entender um pouco mais sobre o ARIMA.
Um modelo ARIMA significa Média Móvel integrada AutoRegressiva, ou seja este tipo de modelo trabalha com a Média Móvel diante de dados históricos para prever o futuro, diferente de alguns outros modelos o ARIMA suporta trabalhar tanto com dados sazonais como dados não sazonais, tudo isso é especificado através de uma série de parâmetros que basicamente categoriza seus dados em tendência,ruido e sazonalidade. Vamos discutir os parâmetros mais importantes do ARIMA o p,d e q.
Primeiramente o parâmetro P associado ao AR do modelo ARIMA, é o parâmetro de regressão dos dados, ou seja, é ele que procura entender como esta se comportando os dados do passado.
O segundo parâmetro D associado ao I do modelo ARIMA, é o parâmetro que busca identificar uma especie de “semelhança” nos dados, ou seja, a diferenciação entre os dados e com isso é possível saber se os dados tem uma grande variancia o que contribui com o cenário de previsão.
Por ultimo o parâmetro Q associado ao MA do modelo ARIMA, é o parâmetro da média móvel do modelo, em outras palavras ele que identificada através do calculo de média móvel a direção da tendência dos dados.
Neste artigo vamos utilizar primeiramente um AutoArima e posteriormente o próprio ARIMA para previsão dos dados. Por curiosidade minha e por ser um conjunto de dados extremamente simples de utilizar e entender eu escolhi um conjunto de dados sobre o cenário do Covid-19 no Brasil, mais especificamente eu selecionei uma amostra desses dados filtrando apenas o meu estado Paraíba para fazer a previsão.
Covid-19 Brazil – Kaggle: https://www.kaggle.com/unanimad/corona-virus-brazil/data?select=brazil_covid19_cities.csv
Hora do código!
Nesta parte do artigo vou mostrar por partes nosso código e ao final do artigo eu disponibilizo o código completo em meu Github.
Primeiramente vamos importar as bibliotecas iniciais:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import time
Apenas um resumo rápido sobre estas bibliotecas para quem não esta familiarizado com analise de dados em Python.
O Pandas é uma biblioteca focada em analise e manipulação de dados, ele oferece funções e operações das mais diversas para manipular um conjunto de dados em forma de tabelas.
O Numpy é uma biblioteca para manipular Arrays e matrizes com varias operações matemáticas que facilitam o trabalho neste tipo de estrutura.
O Matplotlib é a biblioteca mais básica na minha opinião para criação de gráficos, ela é muito útil para visualizar os dados em gráficos de forma rápida durante o trabalho de entendimento do seu conjunto de dados, ela trabalha muito bem com o numpy.
Agora vamos carregar nosso conjunto de dados:
Conforme dito anteriormente, para nossa previsão vou selecionar apenas o estado da Paraíba, portanto vamos aplicar uma filtragem por estado (state):
Agora vamos trabalhar com a coluna date e fazer um somatório de todas as cidades para facilitar a manipulação dos dados e seu uso em um modelo ARIMA. Conforme abaixo estamos definindo a coluna date como índice do nosso dataframe, convertendo seu tipo de dado para Datetime e formatando de acordo com seu formato de data, por fim estamos restringindo as colunas do dataframe para state e cases agrupando apenas por data e realizando o somatório.
Agora abaixo apenas realizei uma filtragem para entender o inicio dos dados e fim dos dados para saber até que data eu tenho de informação:
Até este ponto já fizemos a pequena preparação dos dados para iniciarmos as previsões, reforço aqui que geralmente trabalhar na etapa de preparação de dados leva muito mais tempo e esforço devido a dificuldade de formar um conjunto de dados limpo, neste caso nosso conjunto de dados é simples e não possui dados “sujos” como valores negativos, desformatados, nulos ou de varias fontes.
Agora vamos compreender um pouco mais sobre nosso conjunto de dados, lembra dos conceitos básicos de séries temporais abordado anteriormente? Pois bem, vamos aqui utilizar o Statsmodel para decompor nossos dados e “plotar” em vários gráficos de acordo com sua Tendencia, Sazonalidade e ruido (ou sobra como gosto de chamar)
Analisando os gráficos podemos observar que nosso conjunto de dados possui uma tendencia (não exponencial) e uma sazonalidade, já na parte do resíduo (ou ruido) podemos ver que no inicio não existia uma grande oscilação no entanto depois do dia 4 de maio já começamos a ter algumas variações isso reflete em nosso gráfico original no qual nosso gráfico era apenas uma tendencia e começou a ter algumas sazonalidades e o que nosso gráfico sazonal mostra. Mais a frente eu vou mostrar como essa sazonalidade no final implica em nossa previsão e algumas alternativas de contorno.
Agora vamos analisar as correlações dos nossos dados, no qual aqui não terá muito mistério visto o que já vimos acima:
Acima estamos “plotando” os gráficos de auto correlação e correlação parcial, o interessante desse gráfico é entender como os dados se relacionam ao longo dos dados passados bem como cada período esta distante da área de confiança (faixa azul do gráfico). E os componentes de sazonalidade, tendencia e ruido? Pois bem o ACF busca de qual quer forma uma auto correlação mesmo com estes componentes.
Já o PACF conforme podemos ver ele apenas busca a correlação dos ruídos, repare que perto do período final dos dados temos uma saída das áreas de confiança, isso se deve aquela pequena sazonalidade que vimos nos gráficos anteriores.
Agora vamos treinar nosso modelo ARIMA com o pmdarima:
Explicando os parâmetros selecionados acima:
- df_paraiba – Se trata do próprio conjunto de dados a ser treinado.
- Start_p – se trata do valor inicial dentro do range de aprendizado do valor p (AR).
- Start_d – se trata do valor inicial dentro do range de aprendizado do valor d (I).
- Start_q – se trata do valor inicial dentro do range de aprendizado do valor q (MA).
- Max_p – Valor máximo dentro do range de aprendizado do valor p (AR).
- Max_d – Valor máximo dentro do range de aprendizado do valor d (I).
- Max_q – Valor máximo dentro do range de aprendizado do valor q (MA).
- M – Valor que se referente ao período da diferenciação sazonal, 7 é igual a diário.
- Start_P – Com p maiúsculo é referente ao valor inicial do modelo AR para sazonalidade. Considere 0 por que o padrão é 1.
- Sazonal – Indica se deve usar um ARIMA ou SARIMA, ou seja, o conjunto possui sazonalidade ou não.
- d e D – Indicam a ordem da primeira e das demais diferenciação da sazonalidade, caso não sejam informados, os valores serão selecionados através de um teste de sazonalidade feito pelo próprio modelo.
- Trace – Indica se deve ser impresso o acompanhamento do aprendizado feito pelo modelo.
- Error_action – Indica se deve notificar ou não caso o conjunto de dados tem um problema de dados estacionários (sem possibilidade de prever).
- Suppress_warnings – Indica se todos os warnings devem ser mostrados.
- Stepwise – Indica se deve ser utilizado um algorítimo especifico chamado Stepwise para aprendizado dos parâmetros (Hyperparameter).
Após o treino do nosso modelo vamos imprimir o resultado do AIC que é métrica para avaliação do modelo (quanto menor melhor) e dos parâmetros selecionados pelo modelo:
Vamos agora com nosso modelo treinado fazer uma previsão de 30 dias a partir da ultima data disponível em nosso conjunto de dados original, para isso vamos primeiramente montar uma lista já com os próximos 30 dias para facilitar a montagem de um novo dataframe com os dados originais + dados previstos e por fim gerar o gráfico de resultado:
No código acima, estamos utilizando o pacote datetime para obter o dia atual e com isso voltamos 1 dia da data atual pois estou escrevendo este artigo no dia 16/05/2020 e nosso conjunto de dados remete até o dia 14/05/2020, portanto como queremos prever 30 dias temos que considerar do dia 15/05/2020 em diante.
Por fim utilizando nosso modelo fazemos o predict de um período de 30 dias e o resultado atribuímos a um novo dataframe chamado futuro_forecast com um índice de acordo com o range de dados que criamos.
Aqui utilizamos o pacote Plotly para geração de um gráfico mais apresentável com a linha dos dados + a linha de previsão. Observe que nossa linha de previsão considerou a pequena sazonalidade do inicio de maio e a tendencia para sua projeção.
Testando nosso modelo.
Agora vamos validar nosso modelo, considerar uma previsão de informações já existentes, você verá que essa pequena sazonalidade no final do período dos dados originais vai diferenciar muito do que foi previsto pelo modelo.
Gerando um conjunto de dados de 15 dias a partir de 15 dias atrás.
Gerar um conjunto de dados de aprendizado com menos 15 dias do nosso conjunto de dados original.
Gerar um conjunto de dados de aprendizado com menos 15 dias do nosso conjunto de dados original.
Repare que nesse treino eu não considerei a sazonalidade devido ao nosso conjunto de dados ir até o final de Abril e conforme visto em nosso conjunto de dados original a sazonalidade inicio a partir de 4 de maio.
Conforme podemos observar a previsão de 15 dias seguiu uma tendencia e não a sazonalidade dos dados originais, enquanto a previsão de 30 dias que já visualizamos anteriormente considerou a sazonalidade.
Conclusão
Entendemos ate aqui os conceitos básicos de series temporais, como cada cenário de como os dados se comportam ao longo do tempo tem uma classificação especifica, as mais variadas técnicas matemáticas para padronizar os dados e sobre o modelo ARIMA, sua funcionalidade e sua aplicação utilizando um conjunto de dados simples e limpo para treino,validação e previsão de dados. Existe um mundo de outros algorítimos para ajudar na previsão de dados, deixo aqui a recomendação do estudo sobre o Hotwinters do pacote statsmodel.
Qual quer dúvida estou a disposição, vlw!!!!
Link do código completo: https://github.com/AirtonLira/artigo_series_arima