Going Dutch: Como um brasileiro utilizou Data Science e Machine Learning para encontrar um apartamento em Amsterdam — Parte 1

Gabriel Lages
Data Hackers
Published in
13 min readJul 1, 2018

Entenda como Rafael Pierre, cientista de dados brasileiro utilizou Data Science e Machine Learning para alugar um apartamento na Holanda

Esse post foi originalmente escrito por Rafael Pierre, que me autorizou traduzi-lo para Português. O artigo original tem 2 partes e você pode encontrar a parte 1 aqui ou a parte 2 aqui, os artigos originais estão em inglês.

O mercado imobiliário de Amsterdam tem passado por um momento de aquecimento nos últimos anos, o que tem levado o preço dos imóveis a subir 2 dígitos anualmente desde 2013. Enquanto os donos dos imóveis tem muitas razões para comemorar, o mesmo não ocorre com quem está em busca de um apartamento para comprar ou alugar.

Como estava de mudança para o velho continente, esse cenário se tornou um grande desafio pra mim. Pois dizem que em Amsterdam, o mercado de aluguéis é tão imprevisível quanto o mercado de compra e venda de imóveis. Diante disso, decidi dar uma olhada mais de perto nos imóveis disponíveis para aluguel na cidade, e para isso utilizei de algumas ferramentas (Python, Pandas, Matplotlib, Folium, Plot.ly and SciKit-Learn) com o objetivo de responder as seguintes perguntas:

  • Como é o comportamento da distribuição de preços dos imóveis disponíveis para aluguel?
  • Quais são as regiões mais valorizadas da cidade?
  • Qual a área mais interessante para que eu inicie minha procura?

E em seguida, o mais importante:

  • Seria possível criar um modelo preditivo para o preço de aluguel de um apartamento na cidade?

Dividi minha abordagem nos passos abaixo:

  • Coleta de dados: Utilizando web scrapping no Python, extrai os dados referentes aos preços de aluguéis de alguns sites.
  • Limpeza de dados: Essa é geralmente a parte mais demorada de qualquer processo de análise de dados. Neste caso, é essencial fazer a limpeza do Dataset para que seja possível formatar os dados, remover outliers etc.
  • Análise Exploratória (EDA): A análise exploratória de dados é importante para o entendimento dos dados e para se ter uma visão geral do dataset.
  • Análise Preditiva: Neste passo eu criei, treinei e testei um modelo de machine learning para o dataset com o objetivo de realizar a predição do preço de aluguéis de imóveis em Amsterdam.
  • Feature Engineering: Em busca de um modelo mais robusto, fiz transformações nos dados e inclui novas features baseadas em dados geográficos

Então chegou a hora… Let’s go Dutch

A expressão “Go Dutch” (tornar-se Holandês em tradução livre) se refere ao momento em que pessoas dividem a conta em um bar, restaurante ou outras ocasiões. De acordo com o site The Urban Dictionary, quando o assunto é dinheiro os cidadãos Holandeses são famosos por serem “mãos de vaca”, ou seja, contar até a última moeda e por coincidência ou não, esse é um aspecto que eu também me identifico muito. Essa é uma expressão que vem de séculos passados, devido a rivalidade com os ingleses principalmente no período de guerras entre os países, rivalidade esta que acabou gerando diversos esteriótipos negativos.

Voltando para a análise, vamos agir como Holandeses (“go dutch”) com o objetivo de encontrar as melhores oportunidades.

Como resultado do nosso primeiro passo “Coleta de dados”, extraímos um dataset contendo 1.182 apartamentos para aluguel em fevereiro de 2018 no formato “.csv”.

Vamos começar criando um Data Frame desses dados utilizando o Pandas.

Já sabemos que nosso dataset tem 1.182 ofertas de apartamentos para aluguel. Agora vamos analisar as variáveis e o formato dos dados.

Agora vamos calcular algumas estatísticas para ter uma visão geral dos dados e de sua dispersão.

Neste momento já podemos fazer algumas observações sobre nossos dados:

  • Temos uma coluna aparentemente desnecessária “Unnamed: 0”, como ela não contém nenhuma informação importante podemos remove-la.
  • Algumas colunas estão no formato errado, isso pode se tornar um problema se precisarmos fazer análises baseadas em números e/ou textos. Precisamos converter todas as colunas para os devidos formatos.
  • Observamos que o valor mínimo para a váriavel número de quartos (“number_of_bedrooms”) é 2. Ao mesmo tempo o valor mínimo para o tamanho do apartamento (“apartment_size”) é 10 m². Cruzando essas variáveis acreditamos ser improvável que um apartamento tenha 2 quartos e apenas 10 metros quadrados, não é mesmo? É provável que isso ocorra pois na Holanda os apartamentos não são divulgados levando em consideração o número quartos, mas sim o número de cômodos (ou como eles preferem chamar “kamers”). Neste caso o apartamento de 2 cômodos e 10 m² teria um quarto e uma sala.
  • Algumas colunas do nosso dataset como: name, provider_code, begin_date e city_code não parecem agregar muito valor a nossa análise, então decidimos remove-las.
  • Temos algumas variáveis do tipo data no nosso conjunto de dados, para facilitar a criação de modelos preditivos vamos converter esses campos para o formato integer, utilizando o padrão Unix Epoch.
  • Os preços médios de preços de apartamentos
  • Os preços médios dos aluguéis de apartamentos são de aprox. € 2.225,13 euros e o desvio padrão é de aprox. € 1148,40, isso mostra que nossos dados são muito dispersos. O índice de dispersão (variância/média) é de aproximadamente 592,68.

Análise Exploratória de Dados (EDA)

Após a limpeza dos dados é hora de tentar responder algumas perguntas.

Já extraímos as estatísticas, medidas de posição (mínimo, quartis, máximo) e medidas de dispersão da maioria das variáveis. Porém, acreditamos que seja importante uma análise mais visual, e decidimos gerar um boxplot utilizando a lib plot.ly, gerando um overview das variáveis que pode ser vista abaixo.

Aparentemente temos alguns outliers (valores extremos) — especialmente para apartamentos na região “Amsterdam Centrum”. Provavelmente o volume de pessoas que deseja viver próximo aos canais de Amsterdam e a Museuplein é muito alto .

Com o objetivo de melhorar a assertividade de nossa análise decidimos remover os outliers, criando um novo dataset — aparentemente a linha de corte de €3.000 é um bom limite para os dados normalizados.

Após remover os outliers, as regiões “Amsterdam Zuidoost” e “Amsterdam Nieuw West” aparentemente são boas candidatas para nossas buscas.

Agora, precisamos dar uma olhada na distribuição dos nossos dados.

Através de uma simples inspeção visual nos dados, vemos que aparentemente os dados tendem a uma distribuição normal, mas não é possível termos certeza apenas com essa análise visual.

Por isso é importante medirmos a Assimetria (skewness) e Curtose (kurtosis) da distribuição. (Skewness = 0,5915) (kurtosis = 0,2774).

Um coeficiente de assimetria muito elevado geralmente pode representar um problema para estimar um modelo preditivo, uma vez que vários algorítimos partem do pressuposto que a distribuição dos dados é normal. Esses fatores podem influenciar a forma com que os modelos calculam o erro e causar um viés ao algorítimo.

Por sorte, nesse caso não observamos esse tipo de problema e podemos seguir com nossa análise. Com o objetivo de entender melhor as relações entre as variáveis do dataset geramos uma matriz contendo os gráficos das correlações das variáveis, mais conhecido como pairplot, para gerar esses gráficos utilizamos a lib seaborn no python.

Nos gráficos é possível ver algumas relações interessantes. Algumas variáveis estão linearmente relacionadas, em alguns casos essa relação é trivial como por exemplo quando comparamos o preço do aluguel (normalized_price) com o tamanho do apartamento (apartment_size). Mas, além desses casos observamos algumas outras relações interessantes — Como por exemplo a variável apartment_size versus price_per_meter, que aparentemente estão negativamente correlacionadas.

O próximo passo para seguirmos em frente é cruzarmos os dados para calcular os valores da Correlação de Pearson entre as variáveis. Para isso vamos utilizar novamente a lib Seaborn no python e fazer um mapa de calor (heatmap) com as correlações (para quem ainda não está familiarizado um mapa de calor de correlações é uma matriz de correlações onde os valores são representados em forma de cores, apesar de parecer algo novo essa visualização já existe a séculos e também pode ser chamada de “Shaded Matrix”).

Observando os gráficos é possível identificar alguns aspectos interessantes:

  1. Como já havíamos observado no pairplot, as variáveis “Price per Meter” e “Apartment Size” apresentaram uma considerável correlação negativa com o coeficiente de correlação de Pearson (-0,7). A grosso modo, essa correlação indica que quanto maior o apartamento menor será o preço por metro quadrado, onde por volta de 70% do crescimento do preço por metro quadrado poderia ser explicada pela queda no tamanho do apartamento. É importante observar que essa relação pode estar relacionada a diversos outros fatores mas eu acredito particularmente que essa relação se dá devido a uma maior procura por apartamentos menores, uma vez que Amsterdam é uma cidade que está se consolidando como um destino para pessoas jovens da União Européia que na maioria das vezes se muda para a cidade ainda solteiros, ou como casais jovens que ainda não tem filhos. Mesmo nas famílias que tem filhos, tem sido observado que o número médio de filhos por família tem caído ao longo dos anos em Amsterdam. É bom lembrar que essa conclusão não parte de nenhum estudo científico, mas de uma simples especulação com base em minhas observações e na minha própria experiência.
  2. “Normalized Price” e “Apartment Size” possuem um coeficiente de correlação de pearson de 0,54. Isso significa que eles são correlacionados, mas essa correlação não é muito expressiva. De certa forma esse comportamento era esperado, uma vez que o preço do aluguel geralmente é influenciado por outros fatores como a região onde o apartamento está localizado suas condições gerais e outras características.
  3. Observe que existem duas linhas brancas relacionadas a variável “begin_date”. Isso ocorreu pois todas as observações foram coletadas na mesma data 16/02/2018 e consequentemente todas as observações tinham este mesmo valor na coluna begin_date. Neste caso é obvio que não existe nenhuma relação linear entre esta variável e as demais, portanto decidimos remover essa coluna do nosso dataset.
  4. A correlação entre as variáveis “longitude” e “normalized_price” aparenta ser irrelevante, pois está muito próxima de zero. O mesmo pode ser observado para a correlação entre as variáveis “longitude” e price_per_meter”.

Um olhar mais atento

Nos gráficos anteriores, observamos que algumas variáveis estão correlacionadas, agora vamos dar um zoom para entendermelhor cada uma dessas relações. Para isso, primeiramente vamos analisar a correlação entre as variáveis “size” versus “price”, e logo em seguida “size” versus “price (log_scale)”. Logo em seguida vamos investigar a relação entre as variáveis “price” versus “latitude (log scale)”, uma vez que gostariamos de entender quais são as áreas mais interessantes para procurar um apartamento. Será que o famoso mantra do mercado imobiliário “Localização, Localização, Localização” também se aplica em Amsterdam? Será que esse mesmo mantra é o que define o tamanho dos apartamentos?

Vamos tentar descobrir!

Observando os gráficos acima, não podemos dizer que existe uma relação linear entre estas variáveis. É importante ressaltar que utilizamos a escala logarítmica em alguns gráficos com o objetivo de tentar eliminar possíveis distorções devido as diferenças de escala.

Seria esse o fim da linha?

O fim da linha

Até agora tentamos investigar algumas correlações entre as variáveis e não encontramos muitas informações relevantes relacionadas as colunas “normalized_price”, price_per_meter”, “latitude” ou “longitude”.

Apesar disso, desejávamos analisar os dados de uma forma mais visual, distribuindo as observações de forma geográfica. E se pudéssemos ver um mapa de Amsterdam que desse destaque para as áreas mais caras ou mais baratas?

Utilizando o Folium, uma lib em python com o foco em data visualization, conseguimos criar o mapa abaixo:

Para entender melhor o mapa:

  • O tamanho dos círculos foi definido de acordo com a área dos apartamentos em m², utilizando umas escala de 0 a 1, onde 1 = tamanho máximo observado nos apartamentos pesquisados e 0 = tamamnho mínimo observado.
  • Círculos Vermelhos representam apartamentos com preços mais altos por metro quadrado
  • Círculos Verdes representam justamente o oposto — apartamentos com preços mais baixo por metro quadrado.
  • Ao clicar em cada círculo é possível observar uma caixa de texto contendo algumas informações importantes como, o valor mensal de aluguel em euros “monthly rental price”, e o tamanho do apartamento em m² “apartment size”.

Já nos primeiros segundos do vídeo é possivel notar alguns pontos vermelhos nas áreas onde ficam os canais, região próxima a “Amsterdam Centrum”. Movendo a visualização para outras áreas da cidade como “Amsterdam Zuid”, “Amsterdam Zuidoost”, “Amsterdam West” e “Amsterdam Noord”, podemos observar mudanças nesse padrão— neste caso vemos uma concentração maior de círculos grandes e verdes. É provável que essas áreas possam reunir boas oportunidades de aluguel. Sendo assim, podemos utilizar o mapa para definir a região onde inciaremos a procura.

Será que após todas essas análises finalmente vamos encontrar uma relação entre localização e preços? Ou talvez seja o fim da linha de fato. Talvez não haja uma relação linear entre essas variáveis.

Modelo Random Forests

Random forests ou random decision forests são algorítimos de machine learning baseados em ensemble learning para classificação, regressão e outras aplicações. Estes modelos partem da combinação de múltiplas árvores de decisão (decision trees) durante a etapa de treinamento. Os modelos do tipo Random Forest são muito utilizados com o objetivo de reduzir o “overfitting” que costuma ocorrer em modelos de arvore de decisão.

Os modelos do tipo Random Forests são meus favoritos devido a algumas características:

  • Random Forests não necessita de praticamente nennhuma preparação de dados. Devido a lógica por trás desses modelos, eles não dependem de uma limpeza e preparação de dados muito específica.
  • Random Forests podem ser treinadas rapidamente. Os algorítimos que o modelo utiliza para treinar e diversificar novas árvores apresenta uma ótima performance e desempenho.
  • É difícil estar errado com Random Forests. Ao contrário das redes neurais, modelos de Random Forest não são sensíveis a hiper parâmetros.

Existem várias outras vantagens, mas a lista ficaria enorme. O mais importante agora é utilizar dos benefícios associados a este modelo para tentar prever os preços dos aluguéis de apartamentos com os dados que temos até agora. Nossa variável resposta em nosso modelo Random Forest, ou seja, a variável que tentaremos prever, será “normalized_price”.

Porém, antes de estimar os modelos precisamos fazer alguns passos de feature engineering. Esse passo é necessário pois vamos utilizar as funções de Randopm Forest da lib Scikit-learn no python e ela exige que nosso conjunto de dados atenda a alguns pré-requisitos relacionados a formatação das variáveis categóricas. Primeiramente vamos formatar as variáveis district1 e address e em seguida remover algumas features que não devem ser incluídas no modelo como price_per_meter e normalized_price — caso contrário, teríamos uma inconsistência no modelo, pois nosso ele seria capaz de “trapacear” e adivinhar facilmente os preços dos apartamentos.

Treinando e Testando o modelo

Overfitting, é um grande problema relacionado aos modelos de machine learning e ocorre quando o modelo se ajusta muito bem ao conjunto de dados anteriormente observado, mas se mostra ineficaz para prever novos resultados (geralmente isso ocorre devido a influência de valores extremos e de erros no ajuste do modelo). Modelos com essa característica geralmente tem alta variância e um baixo viés (bias). Modelos mais complexos como Árvores de Decisão, SVM ou Redes Neurais são mais propensos a sofrer as consequências do overfitting. Fazendo uma analogia, um modelo com overfitting seria como um jogador de futebol, que além de ser um bom atacante, faz um trabalho ruim em outras posições, como no meio-campo ou na defesa. Ele é muito bom no ataque, no entanto faz um trabalho ruim nas outras funções.

Uma forma comum de testar se o ajuste do modelo foi impactado pelo overfitting é separando os conjuntos de dados em dados de treino e dados de teste de maneira aleatória. No nosso caso optamos por utilizar 70% dos dados para a base de treino e os 30% de dados restantes vamos armazenar para realizar testes quando o modelo estiver pronto. Se as estatísticas do modelo estimado estiverem satisfatórias vamos submeter o modelo ao conjunto de dados de teste, caso o modelo apresente baixa assertividade é bem provável que tenha ocorrido overfitting.

Showdown: a hora da verdade

Após treinar e testar o modelo temos os seguintes resultados.

Observando a imagem é possível notar que nosso modelo não está fazendo uma predição ruim para os preços de apartamentos. Nosso modelo foi capaz de atingir um score R2 de 0,70, numa escala onde 1 representa o melhor score possível e -1 o pior score possível.

É importante lembrar que esse foi o modelo base. Num segundo post dessa série, eu demonstro como fiz algumas mudanças para obter uma melhoria de 10% no score do modelo (em inglês).

Espero que este post te ajude a avançar como um Data Scientist!

  • Se tiver interesse em ir mais a fundo, você pode encontrar um Jupyter Notebook com os passos dados em python clicando aqui.
  • Lembrando que esse post é uma tradução livre feita pelo Data Hacker Gabriel Lages e que foi autorizada pelo autor Rafael Pierre se você quiser pode conectar com o autor no LinkedIn.
  • Alguma sugestão? pergunta? Fique a vontade para mandar comentários.
  • Não se esqueça de compartilhar o post e seguir a comunidade Data Hackers no medium!
  • No mais, para você chegou até aqui, muito obrigado!

--

--

Gabriel Lages
Data Hackers

Data & Analytics Director at Hotmart, Co-Founder of Data Hackers.