Construindo modelos preditivos por Decision Tree e Random Forest para estimar o preço de casas com base em seus atributos
No mundo da especulação de imóveis, é possível identificar padrões de preços de casas de um passado recente, e usar esses padrões para fazer previsões para as novas casas que estarão à venda.
Para fazer tais previsões, irei comparar neste artigo dois modelos de aprendizado de máquina: Árvore de Decisão e Floresta Aleatória.
O primeiro passo em qualquer projeto de aprendizado de máquina é familiarizar-se com os dados. Para isso, utilizarei a biblioteca Pandas, principal ferramenta que os cientistas de dados usam para explorar e manipular dados. A maioria das pessoas abrevia pandas em seu código como pd:
import pandas as pd
Neste artigo, trabalharei com dados sobre preços de casas em Miami, Flórida (EUA).
Carregando e explorando os dados com os seguintes comandos
miami_ data = pd.read_csv('miami-housing.csv')
miami_data.describe()
Como saída, é possível verificar métricas como quantidade de casas, valor médio dos atributos, bem como valores máximo e mínimo:
Métricas para explorar os dados
Selecionando dados para o modelo
Como o conjunto de dados tem muitas variáveis, vou escolher algumas usando minha intuição.
Para escolher as variáveis/colunas, preciso ver uma lista de todas as colunas no conjunto de dados. Isso é feito com a propriedade columns do DataFrame:
miami_data.columns
E a saída é:
Index(['LATITUDE', 'LONGITUDE', 'PARCELNO', 'SALE_PRC', 'LND_SQFOOT',
'TOT_LVG_AREA', 'SPEC_FEAT_VAL', 'RAIL_DIST', 'OCEAN_DIST',
'WATER_DIST', 'CNTR_DIST', 'SUBCNTR_DI', 'HWY_DIST', 'age',
'avno60plus', 'month_sold', 'structure_quality'],
dtype='object')
Selecionando o alvo da previsão
Usarei a notação de ponto para selecionar a coluna que quero prever, que é chamada de alvo de previsão. Por convenção, o alvo da previsão é denominado y. Portanto, o código que preciso para salvar os preços das casas nos dados de Miami é:
y = miami_data.SALE_PRC
Escolhendo os Atributos
As colunas inseridas no modelo (e posteriormente usadas para fazer previsões) são chamadas de "Atributos". No caso deste artigo, são as colunas utilizadas para determinar o preço da casa. Abaixo é possível visualizar uma lista de nomes das colunas selecionadas:
miami_atributos = ['LND_SQFOOT', 'TOT_LVG_AREA', 'CNTR_DIST', 'age', 'structure_quality']
Onde:
- LND_SQFOOT: land area (square feet) – área do terreno (pés quadrados)
- TOT_LVG_AREA: floor area (square feet) – área útil (pés quadrados)
- CNTR_DIST: distance to the Miami central business district (feet) – distância do distrito comercial central de Miami (pés)
- age: age of the structure – idade da estrutura (casa)
- structure_quality: quality of the structure – qualidade da estrutura
Por convenção, esses dados são chamados de X:
X = miami_data[miami_atributos]
Revisando rapidamente os dados que serão usados para prever os preços das casas
Métricas dos atributos utilizados na previsão
Construindo o Modelo – Árvore de Decisão
Usarei a biblioteca scikit-learn para criar os modelos. Scikit-learn é a biblioteca mais popular para modelar os tipos de dados normalmente armazenados em DataFrames.
As etapas para construir e usar um modelo são:
- Definição: que tipo de modelo será? Uma árvore de decisão? Algum outro tipo de modelo? Alguns outros parâmetros do tipo de modelo também são especificados.
- Ajuste: capturar padrões dos dados fornecidos. Este é o coração da modelagem.
- Previsão: aquilo que se busca.
- Avaliação: determinar quão precisas são as previsões do modelo.
Abaixo um exemplo de definição de um modelo de árvore de decisão com scikit-learn, com ajuste aos recursos e à variável alvo:
from sklearn.tree import DecisionTreeRegressor
miami_model = DecisionTreeRegressor(random_state=1)
miami_model.fit(X, y)
Assim se constrói um modelo ajustado que pode ser usado para fazer previsões.
Validação de modelo
É preciso avaliar quase todos os modelos que se constrói. Existem muitas métricas para indicar a qualidade do modelo, e para este caso usarei uma métrica chamada Erro Médio Absoluto (também chamado MAE), que quanto menor, mais acurácia tem o modelo. Essa métrica é calculada da seguinte maneira:
from sklearn.metrics import mean_absolute_error
predicted_home_prices = miami_model.predict(X)
mean_absolute_error(y, predicted_home_prices)
O Erro Médio Absoluto calculado foi de 721.5068188343382
A métrica que foi calculada pode ser chamada de pontuação “na amostra”. Foi utilizada uma única “amostra” de casas tanto para construir o modelo quanto para avaliá-lo.
E na verdade, o ideal é excluir alguns dados do processo de construção do modelo e, em seguida, usá-los para testar a precisão do modelo em dados que ele não viu antes. Esses dados são chamados de dados de validação.
Assim, alguns desses dados serão usados como dados de treinamento para ajustar o modelo e os outros dados serão usados como dados de validação para calcular o Erro Médio Absoluto.
Com esse ajuste no modelo, o novo Erro Médio Absoluto calculado foi de 89809.16221648005
O MAE passou de aproximadamente 700 dólares para 90 mil dólares.
Esta é a diferença entre um modelo que é quase exatamente correto e outro que é inutilizável para a maioria dos propósitos práticos. Como ponto de referência, o valor médio da casa nos dados de validação é de 400 mil de dólares. Portanto, o erro nos novos dados é de cerca de um quarto do valor médio da casa.
Há muitas maneiras de melhorar este modelo, como fazer testes para encontrar melhores recursos ou diferentes tipos de modelo.
Underfitting e Overfitting
Um bom modelo não pode sofrer de Underfitting nem de Overfitting.
Um cenário de Overfitting ocorre quando, nos dados de treino, o modelo tem um desempenho excelente, porém quando utilizamos os dados de teste o resultado é ruim. Já no caso do Underfitting, o desempenho do modelo já é ruim no próprio treinamento. O modelo não consegue encontrar relações entre as variáveis e o teste nem precisa acontecer.
Existem algumas alternativas para controlar a “profundidade da árvore” e muitas permitem que algumas rotas através da árvore tenham maior profundidade do que outras rotas. O argumento max_leaf_nodes fornece uma maneira muito sensata de controlar o Overfitting versus o Underfitting. Assim, pode-se usar uma função utilitária para ajudar a comparar pontuações MAE de diferentes valores para max_leaf_nodes:
def get_mae(max_leaf_nodes, train_X, val_X, train_y, val_y):
model = DecisionTreeRegressor(max_leaf_nodes=max_leaf_nodes, random_state=0)
model.fit(train_X, train_y)
preds_val = model.predict(val_X)
mae = mean_absolute_error(val_y, preds_val)
return(mae)
Pode-se usar um “loop for” para comparar a precisão de modelos construídos com valores diferentes para max_leaf_nodes:
train_X, val_X, train_y, val_y = train_test_split(X, y, random_state = 0)
for max_leaf_nodes in [5, 50, 500, 1000, 2500, 5000]:
my_mae = get_mae(max_leaf_nodes, train_X, val_X, train_y, val_y)
print("Max leaf nodes: %d \t\t Mean Absolute Error: %d" %(max_leaf_nodes, my_mae))
O resultado obtido foi:
Erros Médios Absolutos para diferentes max_leaf_nodes
Das opções listadas, 1000 é o número ideal de folhas, pois possui o menor MAE.
Floresta Aleatória – Random Forest
As árvores de decisão nos deixam com uma decisão difícil. Uma árvore profunda com muitas folhas terá um ajuste excessivo porque cada previsão vem de dados históricos de algumas poucas casas em sua folha. Mas uma árvore rasa com poucas folhas terá um desempenho ruim porque não consegue capturar tantas distinções nos dados brutos.
Mesmo as técnicas de modelagem mais sofisticadas de hoje enfrentam essa tensão entre o Underfitting e o Overfitting. Porém, muitos modelos têm características específicas que podem levar a um melhor desempenho. Um exemplo desses modelos é a floresta aleatória.
A floresta aleatória usa muitas árvores e faz uma previsão calculando a média das previsões de cada árvore que faz parte da floresta. Geralmente tem uma precisão preditiva muito melhor do que uma única árvore de decisão e funciona bem com parâmetros padrão.
Um modelo de floresta aleatório é construído da mesma forma que uma árvore de decisão no scikit-learn, mas desta vez usando a classe RandomForestRegressor em vez da DecisionTreeRegressor:
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import mean_absolute_error
forest_model = RandomForestRegressor(random_state=1)
forest_model.fit(train_X, train_y)
miami_preds = forest_model.predict(val_X)
print(mean_absolute_error(val_y, miami_preds))
O Erro Médio Absoluto calculado para a Random Forest foi de 68207.22489827461
Provavelmente há espaço para melhorias adicionais, mas esta é uma grande melhoria em relação ao erro da melhor árvore de decisão de 84359. Existem parâmetros que permitem alterar o desempenho da Floresta Aleatória da mesma forma que a profundidade máxima da árvore de decisão única foi alterada. Mas uma das melhores características dos modelos Random Forest é que eles geralmente funcionam razoavelmente mesmo sem esse ajuste.
Conclusão
Para os casos em que se precisa estimar os preços de imóveis, as Árvores de Decisão e as Florestas Aleatórias são ferramentas poderosas no mundo do aprendizado de máquina.
As Árvores de Decisão oferecem simplicidade, interpretabilidade e são mais rápidas de implantar, fazendo delas ideais para conjuntos de dados menores. Não obstante, podem estar sujeitas a Overfitting, especialmente em cenários complexos.
As Florestas Aleatórias, por outro lado, combinam múltiplas árvores de decisão, fornecendo previsões mais precisas e robustas, especialmente em conjuntos de dados grandes e complexos. Esses modelos têm menos probabilidade de Overfitting e geralmente são mais confiáveis, mas ao mesmo tempo exigem mais recursos computacionais.
GitHub
No link abaixo é possível visualizar todo o código escrito e a base de dados:
https://github.com/luisfelipevendramim/decision-tree-and-random-forest/tree/decision-tree-and-random-forest