Como fazer Regressão com Statsmodels no Python

, editado •0•0Comment iconComment iconComment iconComment icon

Regressão linear, ARIMA e regressão multivariada com Statsmodels em Python, com dados reais de ações: como ler o resultado e testar a previsão.

Editar artigo

Material para acompanhar esta aula

Baixe a planilha encontrada aqui no Google Planilhaslink outside website, com o preço diário de 20 ações e do ouro de agosto de 2014 a agosto de 2017. Baixe-a em CSV (Comma-Separated Values), o formato mais comum para guardar uma tabela de dados que qualquer linguagem consegue ler.

Crie um ambiente de desenvolvimento Python 3 ou use um ambiente online já pronto, como o jupyter lab onlinelink outside website, e importe o banco de dados.

Statsmodels em Python

Renomeie o arquivo baixado para "dados-2.csv" para facilitar. Vamos usar os pacotes pandas, numpy, statsmodels e matplotlib. Abaixo você vê como importar cada um:

Importação dos pacotes em python
Importação dos pacotes em python

Tempo como índice

Repare que usamos decimal="," e thousands="." porque os números da planilha estão no formato brasileiro. Agora vamos usar o tempo como índice da tabela e criar uma coluna "Dias" (dias corridos desde o primeiro pregão). Ela será a variável explicativa da regressão linear: o coeficiente angular diz quanto o preço de cada ativo sobe ou desce, em média, por dia.

Transformação para usar o tempo como índice
Transformação para usar o tempo como índice

Duas observações. O df.sort_index() sozinho não faz nada, porque o resultado não é guardado, e no pandas 3.x o inplace=True gera aviso de descontinuação; prefira df = df.set_index('Tempo').sort_index(). E o asfreq("D") cria uma linha para cada dia do calendário: fins de semana e feriados viram NaN, e a tabela passa de 756 pregões para 1.097 dias.

Matriz de correlação

Antes das regressões, uma análise muito importante para quem investe: a matriz de correlação, que mostra o quanto o preço de cada ativo anda junto com o de cada outro. Para montar uma carteira, prefira combinar ativos com correlação baixa ou negativa entre si: quando um cai, o outro tende a não cair junto, e isso diminui o risco. Abaixo está o código para calcular a matriz:

Cálculo das correlações
Cálculo das correlações

A matriz deve ficar assim ao final:

Matriz de correlação entre as ações
Matriz de correlação entre as ações

Abaixo está o que o Python imprimiu. Como a matriz é simétrica, cada par aparece duas vezes. "Dias" não é uma empresa: a correlação com Dias mede a tendência de alta (positiva) ou de queda (negativa) do ativo no período. Correlações mais positivas:

Empresa 1Empresa 2Correlação
BradescoTim0.957497
TimBradesco0.957497
Domino's pizzaDias0.948813
DiasDomino's pizza0.948813
MastercardDomino's pizza0.921368
Domino's pizzaMastercard0.921368
SantanderAmerican Express Company0.888684
American Express CompanySantander0.888684
TimSantander0.888301
SantanderTim0.888301

Correlações mais negativas:

Empresa 1Empresa 2Correlação
DiasSantander-0.642465
SantanderDias-0.642465
Ford motorsBraskem-0.668737
BraskemFord motors-0.668737
Ford motorsMastercard-0.708027
MastercardFord motors-0.708027
Domino's pizzaFord motors-0.826345
Ford motorsDomino's pizza-0.826345
Ford motorsDias-0.892252
DiasFord motors-0.892252

Entre preços com tendência, boa parte da correlação vem só de os dois subirem ou caírem ao longo do tempo. Para montar carteira, o mais adequado é a correlação dos retornos diários: df.pct_change().corr().

Você quer montar uma carteira de duas ações com o menor risco possível. Qual par da tabela é o melhor ponto de partida?

Loading icon

Gabarito: Domino's pizza e Ford motors — com correlação de -0,83, quando uma cai a outra tende a subir, e as oscilações se compensam. Bradesco e Tim (0,96) andam praticamente juntas e quase não diversificam.

Regressão linear simples

Vamos agora de fato usar o Statsmodels. Abaixo está o código para fazer uma regressão linear simples entre o ouro e o número de dias. O sm.add_constant() acrescenta o intercepto, que o OLS do Statsmodels não inclui sozinho.

Regressão linear no Statsmodels
Regressão linear no Statsmodels

A regressão linear traz diversos resultados. Veja a tabela abaixo e tente interpretar cada parâmetro:

OLS resultados
OLS resultados

O coeficiente de Dias (0,0255) diz que o ouro subiu em média 0,026 por dia (uns 9,3 por ano), e o R² de 0,308 diz que o tempo explica só 31% da variação do preço. O número que mais preocupa é o Durbin-Watson de 0,015: o ideal é perto de 2, e perto de zero indica resíduos fortemente autocorrelacionados, o que deixa os erros-padrão e os p-valores otimistas demais. Além disso, as 1.097 observações incluem os fins de semana interpolados; os dados reais são 756.

Abaixo estão nossa previsão e os pontos observados da realidade:

Previsão vs observado
Previsão vs observado

Não é das melhores regressões, né? O preço sobe e desce em ondas que uma reta não acompanha. Vamos olhar também para os resíduos. No histograma abaixo, o eixo horizontal é o valor do resíduo e o vertical, a contagem de dias; os rótulos do código estão trocados.

Os resíduos não são simétricos: cauda longa à direita
Os resíduos não são simétricos: cauda longa à direita

Na regressão do ouro contra os dias, o Durbin-Watson foi 0,015. O que isso indica?

Loading icon

Gabarito: Que os resíduos são fortemente autocorrelacionados, e os p-valores ficam otimistas demais — o Durbin-Watson vai de 0 a 4 e fica perto de 2 sem autocorrelação. Perto de 0, o erro de um dia praticamente repete o do dia anterior, o que viola uma hipótese do OLS.

Modelo ARIMA

Se nossa amiga regressão linear não consegue prever, podemos procurar outros modelos. Vamos tentar um ARIMA(1,1,1) para o preço do ouro. Diferente da regressão, o ARIMA não usa o tempo como variável explicativa: ele explica o preço pelo próprio passado da série (1 termo autorregressivo, 1 diferença e 1 termo de média móvel).

Código python para ARIMA
Código python para ARIMA
Resultado da ARIMA
Resultado da ARIMA
Previsto vs Observado com ARIMA
Previsto vs Observado com ARIMA

A linha vermelha cola nos pontos, mas ela é uma previsão de um passo à frente: cada valor é previsto já sabendo o preço real do dia anterior, e em séries de preço isso sempre fica perto do real. A queda até zero no início também não é erro dos dados: no primeiro dia o modelo não tem passado e devolve zero. Por isso, não podemos nos esquecer de olhar para os resíduos (o filtro abs(x) menor que 40 descarta esse primeiro resíduo, de cerca de 86):

Resíduos da ARIMA
Resíduos da ARIMA

Os resíduos estão centrados em zero e o teste de Ljung-Box (Prob(Q) = 0,76) não encontra autocorrelação sobrando, mas a curtose de 9,08 mostra caudas mais pesadas que as da normal. No gráfico, o eixo horizontal é o resíduo, e não o tempo como diz o rótulo.

No gráfico do ARIMA, a linha prevista quase coincide com os pontos observados. Qual a interpretação correta?

Loading icon

Gabarito: Cada valor ajustado usa o preço real do dia anterior, então é uma previsão de apenas um dia à frente — como o preço de hoje é muito parecido com o de ontem, qualquer modelo que conheça o dia anterior parece ótimo no gráfico. Isso não diz nada sobre prever meses adiante.

Conjunto treino vs conjunto teste

Para ver se o modelo funciona fora da amostra, vamos dividir os dados ao meio: estimamos o modelo com o conjunto treino e verificamos como ele se sai no conjunto teste. O filter(model_fit.params) aplica a série inteira aos parâmetros estimados só com o treino.

Criando o conjunto teste e treino e fazendo nova regressão
Criando o conjunto teste e treino e fazendo nova regressão
Resultados da ARIMA de treino
Resultados da ARIMA de treino

Previsão final:

Teste, Treino e valores observados
Teste, Treino e valores observados

Parece excelente, mas a linha vermelha ainda é a previsão de um passo, que a cada dia do teste recebe o preço real do dia anterior. Refazendo as contas, o erro médio (raiz do erro quadrático médio) dela no teste é 1,71, praticamente igual ao de dizer que o preço de amanhã será o de hoje (1,72). A previsão verdadeira para todo o teste, sem olhar os dados dele, é model_fit.forecast(steps=len(teste)): ela fica quase plana, perto de 71, enquanto o ouro passou de 120, e o erro médio sobe para 22,6. Ou seja, o ARIMA(1,1,1) descreve bem a série dia a dia, mas não antecipa as grandes subidas e descidas.

No teste, a previsão de um passo do ARIMA teve erro médio de 1,71, e a regra 'amanhã igual a hoje' teve 1,72. O que se conclui?

Loading icon

Gabarito: O ARIMA quase não acrescenta nada à regra ingênua de repetir o preço de ontem — comparar com um modelo ingênuo é o jeito mais simples de saber se um modelo de série temporal tem valor, e aqui a diferença é de 0,01.

Regressão multivariada

Caso você não queira trabalhar com ARIMA, é possível fazer uma regressão multivariada, usando ações correlacionadas com a sua como variáveis explicativas. No exemplo abaixo, uso o preço da Chevron e o número de dias para explicar o preço da Vale (antiga Vale do Rio Doce).

Código python para multivariada
Código python para multivariada
Resultado da Regressão Multivariada
Resultado da Regressão Multivariada

O R² sobe para 0,72, mas o coeficiente de Dias tem p-valor 0,538: depois de incluir a Chevron, o tempo não acrescenta nada. O Durbin-Watson de 0,025 repete o alerta: entre preços com tendência, o R² alto pode ser uma regressão espúria.

Previsto e observados pela Regressão Multivariada
Previsto e observados pela Regressão Multivariada

No gráfico, o título e o eixo vertical ficaram com os rótulos do exemplo do ouro; o que aparece ali é o preço da Vale.

Na regressão da Vale contra Dias e Chevron, o coeficiente de Dias teve p-valor 0,538. O que fazer com essa variável?

Loading icon

Gabarito: Ela pode ser retirada, porque não acrescenta poder explicativo depois da Chevron — com p-valor de 0,538 não dá para rejeitar que o coeficiente seja zero. Isso não quer dizer que a Vale não variou no tempo: a variação dela já está capturada pela Chevron.

Exercícios

Agora faça você:

1) Importe esse conjunto no pandas.

2) Faça a matriz de correlação.

3) Escolha uma ação e faça uma regressão linear entre ela e os dias. Não pode ser o ouro!

4) Escolha uma ação e ajuste um ARIMA para ela.

5) Escolha uma ação, treine um ARIMA com metade dos dados e teste com a outra metade. Compare o erro com o da regra 'amanhã igual a hoje'.

6) Desafio: faça uma regressão multivariada que tente explicar o valor de uma ação usando o tempo e o valor de outra ação como referência.

O que você achou deste artigo?

0%
Nota dos usuários (0)

Compartilhe este artigo!