Previsão do número de homicídios no Rio de Janeiro (Sim, eu voltei a postar!!!)

Um pequeno disclaimer: Depois de muito relutar, estou voltando com as atividades do blog. Isso significa de maneira prática, que apesar do clipping ser o grande driver dos acessos, sinto que há uma lacuna em relação a posts técnicos aqui na blogosfera brasileira.

Dessa forma, vou fazer mais posts técnicos com assuntos ligados à Machine Learning, Data Mining e afins.

Disclaimer feito, bora pro post original.

*******

Fala pessoal, tudo bem?

Um dos principais problemas em utilizar processadores numéricos como o Excel ou mesmo o LibreOffice é que se perde um pouco a flexibilidade de parametrizar os modelos de previsão.

Além disso, há um problema grave nesses processadores de reprodutibilidade, dado que pode haver inúmeras versões, planilhas voando pra todo o lado via e-mail, e por aí vai.

Nesse post eu vou utilizar dados reais da quantidade de homicídios que houveram no Rio de Janeiro de 1991 até 2011.

Os dados foram extraídos e consolidados pelo CESeC – Centro de Estudos de Segurança e Cidadania e o link está no final do script.

Antes de mais nada, vamos carregar o package Forecast:

# Load library
if(!require(forecast)){
 install.packages("forecast")
 library(forecast)
}

Depois disso, vamos realizar a carga dos dados. Nesse caso eu fiz uma transformação na planilha original e passei os dados para csv.

# Dataset
rj_murder <- read.csv("https://raw.githubusercontent.com/fclesio/learning-space/master/Datasets/rj-homicidios-1991-2011.csv")

Vamos dar uma olhada nos dados para nos certificar que tudo está OK.

# Check data
head(rj_murder)

Com os dados OK, para incluir um conjunto de dados no package de Forecast e ARIMA, temos que antes de mais nada, pegar todos os datapoints e construir uma série através de um objeto de timeseries como no bloco de código abaixo:

# Transform in time series dataset all metrics inside the dataset 
rj_murder_total <- ts(rj_murder$total, start=c(1991, 1), end=c(2011, 12), frequency=12)
rj_murder_capital <- ts(rj_murder$capital, start=c(1991, 1), end=c(2011, 12), frequency=12)
rj_murder_baixada <- ts(rj_murder$baixada, start=c(1991, 1), end=c(2011, 12), frequency=12)
rj_murder_interior <- ts(rj_murder$interior, start=c(1991, 1), end=c(2011, 12), frequency=12)

Para entendermos o que aconteceu, vamos destrinchar erssa função TS:

ts() função para a construção de série temporal

rj_murder$total conjunto de datapoints do dataframe da coluna total

start=c(1991, 1) início da série é janeiro de 1991

end=c(2011, 12) o fim da série é dezebro de 2011

frequency=12 como estamos falando de dados mensais, a frequencia da série é de 12 datapoints por ano

Agora que entendemos o que fizemos, vamos dar uma olhada nos nossos objetos ts() e ver se os mesmos estão corretos.

#Plot series
par(mfrow=c(2,2))

plot(rj_murder_total
 ,main = "Total de Homicidios no RJ de 1991-2011"
 ,xlab = "Ano"
 ,ylab = "Qtde Homicidios"
 ,type = "l"
 ,lwd = 2.5
 )


plot(rj_murder_capital
 ,main = "Total de Homicidios no RJ de 1991-2011 (Capital)"
 ,xlab = "Ano"
 ,ylab = "Qtde Homicidios"
 ,type = "l"
 ,lwd = 2.5
)


plot(rj_murder_baixada
 ,main = "Total de Homicidios no RJ de 1991-2011 (Baixada)"
 ,xlab = "Ano"
 ,ylab = "Qtde Homicidios"
 ,type = "l"
 ,lwd = 2.5
)


plot(rj_murder_interior
 ,main = "Total de Homicidios no RJ de 1991-2011 (Interior)"
 ,xlab = "Ano"
 ,ylab = "Qtde Homicidios"
 ,type = "l"
 ,lwd = 2.5
)

 

Homicidios RJ

 

Agora que vimos que as nossas séries estão corretas, vamos criar alguns objetos usando a função auto.arima().

# Fit ARIMA models
fit_rj_murder_total <- auto.arima(rj_murder_total)
fit_rj_murder_capital <- auto.arima(rj_murder_capital) 
fit_rj_murder_baixada <- auto.arima(rj_murder_baixada)
fit_rj_murder_interior <- auto.arima(rj_murder_interior)

Essa função retorna o melhor modelo ARIMA de acordo com os valores de AIC, AICc e BIC.

Mas deixando um pouco a teoria de lado, vamos ver como ficaram os ajustes dos modelos ARIMA de acordo com cada uma das séries.

#Plot ARIMA Models
par(mfrow=c(2,2))
plot(forecast(fit_rj_murder_total,h=12)
 ,main = "Total de Homicidios no RJ de 1991-2011 \n Previsão usando ARIMA"
 ,xlab = "Ano"
 ,ylab = "Qtde Homicidios"
 ,type = "l"
 ,lwd = 2.5)

plot(forecast(fit_rj_murder_capital,h=12)
 ,main = "Total de Homicidios no RJ de 91-2011 (Capital) \n Previsão usando ARIMA"
 ,xlab = "Ano"
 ,ylab = "Qtde Homicidios"
 ,type = "l"
 ,lwd = 2.5)

plot(forecast(fit_rj_murder_baixada,h=12)
 ,main = "Total de Homicidios no RJ de 91-2011 (Baixada) \n Previsão usando ARIMA"
 ,xlab = "Ano"
 ,ylab = "Qtde Homicidios"
 ,type = "l"
 ,lwd = 2.5)

plot(forecast(fit_rj_murder_interior,h=12)
 ,main = "Total de Homicidios no RJ de 91-2011 (Interior) \n Previsão usando ARIMA"
 ,xlab = "Ano"
 ,ylab = "Qtde Homicidios"
 ,type = "l"
 ,lwd = 2.5)

 

ARIMA

 

Um bom resultado, mas agora vamos ver o que conseguimos fazer usando o package forecast default, com o horizonte de previsão de 12 meses:

#Forecasting using confidence intervals in 80%, 95% and 99% with 12 months ahead
ahead_rj_murder_total <- forecast(rj_murder_total, level=c(80, 95, 99), h=12)
ahead_rj_murder_capital <- forecast(rj_murder_capital, level=c(80, 95, 99), h=12)
ahead_rj_murder_interior <- forecast(rj_murder_interior, level=c(80, 95, 99), h=12)
ahead_rj_murder_baixada <- forecast(rj_murder_baixada, level=c(80, 95, 99), h=12)

Modelos ajustados, vamos plotar os resultados:

#Plot forecasting
par(mfrow=c(2,2))
plot(ahead_rj_murder_total
 ,main = "Total de Homicidios no RJ de 91-2011 (Total) \n Previsão usando Forecast package"
 ,xlab = "Ano"
 ,ylab = "Qtde Homicidios"
 ,type = "l"
 ,lwd = 2.5
 ,shadecols="oldstyle")

plot(ahead_rj_murder_capital
 ,main = "Total de Homicidios no RJ de 91-2011 (Capital) \n Previsão usando Forecast package"
 ,xlab = "Ano"
 ,ylab = "Qtde Homicidios"
 ,type = "l"
 ,lwd = 2.5
 ,shadecols="oldstyle")

plot(ahead_rj_murder_baixada
 ,main = "Total de Homicidios no RJ de 91-2011 (Baixada) \n Previsão usando Forecast package"
 ,xlab = "Ano"
 ,ylab = "Qtde Homicidios"
 ,type = "l"
 ,lwd = 2.5
 ,shadecols="oldstyle")

plot(ahead_rj_murder_interior
 ,main = "Total de Homicidios no RJ de 91-2011 (Interior) \n Previsão usando Forecast package"
 ,xlab = "Ano"
 ,ylab = "Qtde Homicidios"
 ,type = "l"
 ,lwd = 2.5
 ,shadecols="oldstyle")

Forecast Package Predictions

Podemos ver que tanto usando o modelo ARIMA quanto com o uso do package forecast vimos que haverá uma queda no número de homicídios. Com isso podem ser elaboradas (usando mais dados) políticas públicas de segurança.

Refs:

[1] – http://www.inside-r.org/packages/cran/forecast/docs/auto.arima

[2] – http://www.ucamcesec.com.br/wordpress/wp-content/uploads/2011/04/RJ_2011_evolucao.xls

[3] – http://www.statmethods.net/advstats/timeseries.html

 

Previsão do número de homicídios no Rio de Janeiro (Sim, eu voltei a postar!!!)

Escolha de Variáveis

Um dos maiores desafios na construção de modelos de classificação e de modelos preditivos é saber escolher as variáveis corretas para inclusão no modelo.

Como foi falado aqui em inúmeras vezes, antes de cometer o erro clássico de escalar hardware e software antes de analisar os dados, mesmo que superficialmente; veja se as variáveis do modelo estão adequadas.

Neste excelente vídeo de um webnar da Salford Systems sobre importância das variáveis usando CART isso é explicado de maneira bem simples.

O Dan Steinberg neste vídeo fala da importância de se saber importância das variáveis no modelo, no qual não somente essas variáveis vão dar o aspecto de compreensão relativa a qual o espectro de dados são pertinentes para as tarefas do algoritmo; como também, entender essa importância pode dar subsídio para outras análises que por ventura venham a eliminar a fragilidade do modelo.

Um dos aspectos levantados foi que antigamente para levantamento da importância dessas variáveis eram usados técnicas de regressão as quais de acordo os respectivos coeficientes regressores  eram utilizados como maneira de ranquear as variáveis.

Contudo, com as técnicas mais modernas de análise de dados, e em especial com novos algoritmos, e a necessidade de modelos que além de terem um alto poder de classificação e predição devem ser compreensíveis, conhecer a importância de cada uma das variáveis ajuda entender o grau de especificidade do modelo.

Em outras palavras, essa atividade auxilia no entendimento do papel – ou força – de cada uma das variáveis no modelo.

Uma heurística interessante que foi explicada no vídeo é conhecida como Leave-One-Variable-Out (LOVO).

A técnica de LOVO consiste em retirar sistematicamente uma variável por vez do modelo, e após isso o modelo preditivo é gerado sem essa variável e de acordo com a variância, isto é, a degradação dos resultados, esse processo auxilia em medir o quanto o modelo perde se aquela variável sair.

Essa heurística é extremamente válida em casos em que se trabalha com heurísticas como Redes Neurais Artificiais, no qual muitas vezes mesmo com alterações em parâmetros de arquitetura (Hidden Layers, Neurônios de Entrada, Neurônios de Saída, Momentum, Taxa de Aprendizado, etc) não há uma visão tão nítida da influência da variável na convergência do modelo.

Escolha de Variáveis

Passos para a criação de um projeto de Modelagem Preditiva

Neste post da Salford Systems tem um guia com nove fases:

1) Entendimento do negócio (especificação e um objetivo)

2) Inventário de dados e entendimento

3) Avaliação de dados para adequação nas técnicas

4) Projeto Piloto

5) Preparação (e exploração) dos dados

6) Modelagem (construção de modelos preditivos)

7) Avaliação, Interpretação, Entendimento

8) Projeto Completo

9) Implantação

Passos para a criação de um projeto de Modelagem Preditiva

Amostragem: Precisamos mesmo de 3 divisões amostrais (treinamento, validação e teste)?

Neste artigo do Dan Steinberg ele responde de forma clara:

“The short answer to this question is “no” we do not think that the 3-way partition is mandatory for SPM core models such as CART and TreeNet.”

Confesso que fiquei assustado com a resposta, mas abaixo no próprio artigo ele coloca a justificativa:

“The question we address here is whether this is really enough when the process of model development is lengthy and may involve the building of dozens, hundreds, or even thousands of models. If each model is evaluated on the second data partition one might argue that we are in fact learning from it. The learning may be limited and indirect, but the cumulative effect of intensive model development and evaluation blunts the independence of the second partition data.”

Uma das lutas mais ingratas de quem está trabalhando em um modelo de dados é o fantasma do Overfitting em qualquer modelo de descrição/predição.

O ponto principal do autor é que nem sempre em cenários nos quais os dados são escassos a utilização de amostras ‘holdout‘, isto é, fora do conjunto de dados (treinamento e teste) é necessária.

No artigo tem os resultados de um teste em que houve a construção de um modelo com holdout e sem holdout, e tirando-se as diferenças entre as curvas ROC dos modelos chegou-se ao ótimo resultado de apenas de – 0.00216 em relação ao modelo sem holdout.

Questionamentos metodológicos, e principalmente em relação à possível (ou a ausência de) variância do dados, o ponto é importante e vale a pena ser refletido.

Como é de conhecimento geral, nem sempre na construção de modelos preditivos/descritivos tem-se acesso completo aos dados, e em muitas vezes o volume de dados é extremamente pequeno.

Uma das alternativas para esse tipo de problema é a aplicação do método de Cross-Validation (k=10) que gera resultados satisfatórios.

No entanto, como o autor coloca em questão, um modelo deve ser sempre refinado de forma iterativa e incremental; o que significa que nenhum modelo ‘nasce’ sujeito a erros, mesmo se não houver representatividade das instâncias de ‘validação’.

Neste outro post tem um artigo bem interessante sobre o tema também.

Amostragem: Precisamos mesmo de 3 divisões amostrais (treinamento, validação e teste)?