Por Hyan Dias Tavares • Nov 04, 2021
AIRBNB
RIO DE JANEIRO
NEW YORK
DADOS
Quando você pensa em viajar e conhecer novos lugares, qual é a primeira plataforma que vem a sua mente para alugar um alojamento? Se pensou no Airbnb, saiba que você é um dos 150 milhões de pessoas que também escolheriam ele.
O Airbnb já é considerado como a maior empresa hoteleira da atualidade. E um detalhe importante, eles não possuem nenhum hotel!
Ele conecta pessoas que querem viajar (e se hospedar) com anfitriões que querem alugar seus imóveis de maneira prática. O Airbnb fornece uma plataforma inovadora para tornar essa hospedagem alternativa.
A startup foi fundada em 2008, na Califórnia (EUA) e ganhou o mundo. E mesmo em um momento pandêmico, sua receita no primeiro trimestre de 2021 foi de US $ 887 milhões, um valor 5% maior que o primeiro trimestre de 2020.
Mas algo que leva a discussões são as ações estratégicas que o Airbnb toma para atrair novos anfitriões, principalmente quando comparado aos mercados hoteleiros do Brasil com o dos Estados Unidos.
E como bons Rebels que somos, iremos explorar os dados de ambos os mercados em busca de entender as características, diferenças e deficiências. E para isso vamos escolher duas grandes cidades famosas pelo turismo, ambas estão localizadas em litorais.
Lembrando que o nosso objetivo é introduzir você na análise de dados e mostrar algumas técnicas que poderão ser replicadas para outros cenários. Mas fique tranquilo e não se assuste, irão haver outros artigos/projetos que nos iremos debulhar mais profundamente algumas técnicas e ferramentas. Quero apenas que você consiga desenvolver a mentalidade e entender a importância do uso de dados para desenvolvimento de ações estratégicas, principalmente no marketing.
Uma das maiores cidades do mundo, conhecida pelas corridas de cavalos, pubs de jazz e o grande volume de turistas.
Ela atrai anualmente cerca de 36 milhões de visitantes, como previsto pelo NYC & Company.
New York tem:
Curiosidade: 37% dos nova-iorquinos nasceram em outros países.
A origem do seu apelido “Big Apple” gerou debates durante alguns anos, mas segundo historiadores, o nome surgiu através de uma crítica do escritor Edward S. Martin, sobre a distribuição de renda dos americanos, descrevendo como os Estados Unidos fosse uma grande árvore e os estados seus frutos. Fazendo questionar se New York era apenas mais um dos frutos dessa árvore, por que a “Grande Maçã” deveria receber uma parte desproporcional da riqueza do país?
Sei que nesse momento você está se questionando, o que isso tem relação com a análise de dados e o Airbnb?
“Lembre-se que dados são apenas números, e para gerar informação é preciso conectá-los a fatos históricos e presentes”.
New York é uma cidade que cresceu impactada diretamente pelas políticas públicas e também pelas ações de corporações privadas além de ter sido capital dos Estados Unidos quando ainda era colônia britânica. E como bons analistas não escolhemos essa cidade à toa, pois essa é uma característica que se assemelha a cidade brasileira na qual iremos compará-la, o Rio de Janeiro, que também já foi capital do brasil quando ainda era uma colônia portuguesa.
Uma das maiores metrópoles, que atrai turistas do mundo inteiro, especialmente por suas belezas naturais, carnaval e boemia.
1.2 milhões de turistas internacionais vão ao Rio todos os anos, de acordo com o governo brasileiro.
Rio de Janeiro tem:
Curiosidade: o Rio tem a maior floresta urbana do mundo, que corresponde a 10% do seu território.
A expressão “cidade maravilhosa” ainda é alvo de muitas teorias, entre todas a mais plausível, foi quando um jornal “O Paiz” se referiu ao Rio de Janeiro durante o carnaval de 1904, expressando sua admiração pela calorosa alegria dos cidadãos. A partir desse momento muitos jornalistas, escritores, músicos e poetas começaram a usar essa expressão, que chegou a virar o hino da cidade.
E isso reflete especialmente na personalidade cultural dos moradores, são pessoas que amam e admiram sua cidade, efeito esse na qual New York também é conhecida.
Mas chega de introdução e vamos direto ao ponto. Esse é o momento que vamos utilizar algumas técnicas para carregar, tratar e analisar nossos dados.
E para essa tarefa iremos usar a linguagem de programação Python, pelos fatores de:
Para quem não sabe, o Airbnb possui um projeto na qual disponibiliza os dados das principais cidades do mundo, por meio do portal Inside Airbnb. Seu objetivo é fornecer dados que quantifiquem o impacto dos aluguéis, incentivando o desenvolvimento de soluções em Data Science que ajude comunidades residenciais e de habitação.
O primeiro passo é entrar no portal e escolher as cidades na qual você irá analisar, minha sugestão é usar os arquivos listings.csv, pois contém informações mais resumidas e focadas para nossas necessidades.
Atenção: O portal está em constante mudança, e existe a possibilidade do conjunto de dados utilizados ser atualizado ou removido, não estando mais disponível, o que poderá trazer erros no código.
E para resolver isso, disponibilizei os arquivos New York e Rio de Janeiro, diretamente do meu Dropbox, para que possa replicar esse processo em outros momentos.
Vamos importar todos os pacotes e módulos que iremos utilizar. Bora abrir sua IDE ou o google colab.
In [1]:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from IPython.display import display
from matplotlib import pyplot
%matplotlib inline
Uma dica para quem usar o Dropbox, quando você gera um link para compartilhar o seu Dataset (csv), note que no final do link vai haver o código dl=0, altere ele para dl=1, assim você irá informar ao Dropbox que queremos o arquivo Excel e não o HTML.
Vamos importar os arquivos listings.csv para os dataframe dfNY (New York) e dfRJ (Rio de Janeiro).
In [2]:
dfNY = pd.read_csv("https://www.dropbox.com/s/8i2nw6bd5ha7vny/listingsNY.csv?dl=1")
dfRJ = pd.read_csv("https://www.dropbox.com/s/yyg8hso7fbjf1ft/listingsRJ.csv?dl=1")
Esse é o momento onde vamos ter o primeiro contato com o dataframe. Precisamos entender quais informações estão contidas dentro dele, como está estruturado, o que é cada variável e assim por diante. E como sou bonzinho já vou deixar aqui o dicionário de variáveis.
id – O número de identificação do imóvel.
name – Nome da propriedade anunciada.
hot_id – O número de identificação do proprietário (anfitrião) do imóvel.
neighbourhood_group – É um conjunto de grupos de bairros.
latitude – Coordenada de Latitude do imóvel.
longitude – Coordenada de Longitude do imóvel.
room_type – O tipo de quarto oferecido.
price – Preço por pernoite do imóvel a ser alugado na moeda local.
minimum_nights – Noites mínimas para locação.
number_of_reviews – Quantidade de avaliações que o imóvel recebeu.
last_review – Data da última avaliação.
reviews_per_month – Quantidade de avaliações por mês.
calculated_host_listings_count – Quantidade de imóveis do mesmo anfitrião.
availability_365 – Número total de dias em que o anúncio está disponível durante o ano.
number_of_reviews_ltm – Quantidade de avaliação nos últimos 12 meses.
license – Esta coluna não contém nenhum valor válido.
Vamos investigar os dados de cada dataframe e analisar as 5 primeiras entradas com os comandos.
In [3]:
display(dfNY.head(5))
display(dfRJ.head(5))
Out [3]:
New York
id | name | host_id | host_name | neighbourhood_group | neighbourhood | latitude | longitude | room_type | price | minimum_nights | number_of_reviews | last_review | reviews_per_month | calculated_host_listings_count | availability_365 | number_of_reviews_ltm | license | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
3 | 5136 | Spacious Brooklyn Duplex, Patio + Garden | 7378 | Rebecca | Brooklyn | Sunset Park | 4066265 | -7399454 | Entire home/apt | 275 | 5 | 2 | 2021-08-08 00:00:00 | 0.02 | 1 | 204 | 1 | NaN |
0 | 2595 | Skylit Midtown Castle | 2845 | Jennifer | Manhattan | Midtown | 4075356 | -7398559 | Entire home/apt | 150 | 30 | 48 | 2019-11-04 00:00:00 | 0.33 | 3 | 340 | 0 | NaN |
1 | 3831 | Whole flr w/private bdrm, bath & kitchen(pls r... | 4869 | LisaRoxanne | Brooklyn | Bedford-Stuyvesant | 4068494 | -7395765 | Entire home/apt | 76 | 1 | 408 | 2021-06-29 00:00:00 | 5.03 | 1 | 208 | 58 | NaN |
4 | 5178 | Large Furnished Room Near B'way | 8967 | Shunichi | Manhattan | Midtown | 4076457 | -7398317 | Private room | 68 | 2 | 490 | 2021-08-14 00:00:00 | 3.64 | 1 | 243 | 17 | NaN |
2 | 5121 | BlissArtsSpace! | 7356 | Garon | Brooklyn | Bedford-Stuyvesant | 4068535 | -7395512 | Private room | 60 | 30 | 50 | 2016-06-05 00:00:00 | 0.54 | 1 | 365 | 0 | NaN |
Rio de Janeiro
id | name | host_id | host_name | neighbourhood_group | neighbourhood | latitude | longitude | room_type | price | minimum_nights | number_of_reviews | last_review | reviews_per_month | calculated_host_listings_count | availability_365 | number_of_reviews_ltm | license | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 17878 | Very Nice 2Br in Copacabana w. balcony, fast WiFi | 68997 | Matthias | NaN | Copacabana | -2296599 | -4317940 | Entire home/apt | 350 | 4 | 265 | 2021-05-21 00:00:00 | 2.07 | 1 | 314 | 12 | NaN |
1 | 24480 | Nice and cozy near Ipanema Beach, w/ home office | 99249 | Goya | NaN | Ipanema | -2298405 | -4320189 | Entire home/apt | 297 | 3 | 85 | 2017-04-22 00:00:00 | 0.86 | 1 | 30 | 0 | NaN |
2 | 25026 | Beautiful Modern Decorated Studio in Copa | 102840 | Viviane | NaN | Copacabana | -2297735 | -4319105 | Entire home/apt | 160 | 7 | 238 | 2019-04-27 00:00:00 | 1.86 | 2 | 266 | 0 | NaN |
3 | 35636 | Cosy flat close to Ipanema beach | 153232 | Patricia | NaN | Ipanema | -2298839 | -4319232 | Entire home/apt | 271 | 2 | 181 | 2019-12-06 00:00:00 | 1.92 | 1 | 151 | 0 | NaN |
4 | 35764 | COPACABANA SEA BREEZE - RIO - 20 X Superhost | 153691 | Patricia Miranda & Paulo | NaN | Copacabana | -2298107 | -4319136 | Entire home/apt | 121 | 3 | 371 | 2019-06-15 00:00:00 | 3.05 | 1 | 30 | 35 | NaN |
Precisamos entender qual o volume de dados que possuímos para ambos os dataframes. Lembrando que estamos usando uma versão com dados resumidos, se quiser fazer uma análise mais profunda, sugiro utilizar os arquivos listings.csv.gz.
In [4]:
print(f'New York\nEntradas: {dfNY.shape[0]}\nVariáveis: {dfNY.shape[1]}\n')
print(f'Rio de Janeiro\nEntradas: {dfRJ.shape[0]}\nVariáveis: {dfRJ.shape[1]}\n')
Out [4]:
New York
Entradas: 36923
Variáveis: 18
Rio de Janeiro
Entradas: 23414
Variáveis: 18
New York possui um volume de entradas superior ao do Rio de Janeiro, provavelmente pelo fato de apresentar uma população maior, além de receber mais turistas. Mas essa diferença não será significativa para a nossa análise. Já que iremos observar mais os comportamentos e frequências do que suas intensidades.
Os atributos dos dados ou tipos primitivos, são os formatos dos dados no qual a linguagem (Python) irá interpretar. E te apresentarei 3 que são os mais importantes no momento.
O python interpreta que tudo é um objeto (object), ou seja, quando não se sabe o atributo, ele entende que aquilo é uma string. E para examinarmos os atributos das nossas variáveis bastas digitar.
In [5]:
display(dfNY.dtypes)
Out [5]:
Tipo dos dados por variáveis
id int64
name object
host_id int64
host_name object
neighbourhood_group object
neighbourhood object
latitude float64
longitude float64
room_type object
price int64
minimum_nights int64
number_of_reviews int64
last_review object
reviews_per_month float64
calculated_host_listings_count int64
availability_365 int64
number_of_reviews_ltm int64
license float64
dtype: object
Todos os dados parecem fazer sentido aos seus atributos. Uma exceção é a variável last_review que são datas, mas nosso dataframe entende que ele é uma string. Para isso precisamos mudar ele para o atributo datatime64, que é um atributo específico para datas.
In [6]:
dfNY.last_review = pd.to_datetime(dfNY.last_review, format="%Y-%m-%d")
dfRJ.last_review = pd.to_datetime(dfRJ.last_review, format="%Y-%m-%d")
Se você é esperto, já deve ter notado que o price do Rio de Janeiro é diferente do New York, pelo fato de um país usar a moeda em Dólar e o outro em Real. Para ter um comparativo mais justo e equalizado, é preciso converter o price de New York de Dólar para Real, então faremos isso usando a média das cotações de câmbio de cada ano.
Desta forma, criamos uma nova coluna com apenas os anos da última avaliação, e usando a função mask, relacionamos como restrição a data para usar a cotação média daquele ano respectivo.
In [7]:
import datetime as dt
dfNY['year'] = dfNY.last_review.dt.year
dfNY.price = dfNY.price.mask(dfNY.year <= 2011, (dfNY.price * 1.674))
dfNY.price = dfNY.price.mask(dfNY.year == 2012, (dfNY.price * 1.954))
dfNY.price = dfNY.price.mask(dfNY.year == 2013, (dfNY.price * 2.157))
dfNY.price = dfNY.price.mask(dfNY.year == 2014, (dfNY.price * 2.353))
dfNY.price = dfNY.price.mask(dfNY.year == 2015, (dfNY.price * 3.331))
dfNY.price = dfNY.price.mask(dfNY.year == 2016, (dfNY.price * 3.489))
dfNY.price = dfNY.price.mask(dfNY.year == 2017, (dfNY.price * 3.190))
dfNY.price = dfNY.price.mask(dfNY.year == 2018, (dfNY.price * 3.654))
dfNY.price = dfNY.price.mask(dfNY.year == 2019, (dfNY.price * 3.943))
dfNY.price = dfNY.price.mask(dfNY.year == 2020, (dfNY.price * 5.155))
dfNY.price = dfNY.price.mask(dfNY.year == 2021, (dfNY.price * 5.352))
Tratar os valores ausentes corretamente é uma das partes importantes da análise de dados. Os valores ausentes podem ser representados de muitas maneiras, entre elas como nulos, células vazias, com o valor NAN ou um valor artificial como 9999.
E para identificar a quantidade de valores ausentes de cada dataframe, usaremos o isnull().sum(). E também criaremos uma lista com os dados para podermos compará-los usando o comando pd.DataFrame.
In [8]:
variaveis = ['id',
'name',
'host_id',
'host_name',
'neighbourhood_group',
'neighbourhood',
'latitude',
'longitude',
'room_type',
'price',
'minimum_nights',
'number_of_reviews',
'last_review',
'reviews_per_month',
'calculated_host_listings_count',
'availability_365',
'number_of_reviews_ltm',
'license']
vz = []
dado = []
for i in variaveis:
dado.append(dfNY[i].isnull().sum() / dfNY[i].shape[0])
dado.append(dfRJ[i].isnull().sum() / dfRJ[i].shape[0])
vz.append(dado[:])
dado.clear()
vz
pd.DataFrame(vz, columns=['New York', 'Rio de Janeiro'], index=variaveis)
Out [8]:
New York | Rio de Janeiro | |
---|---|---|
id | 0.000000 | 0.000000 |
name | 0.000352 | 0.000897 |
host_id | 0.000000 | 0.000000 |
host_name | 0.003006 | 0.000769 |
neighbourhood_group | 0.000000 | 1000000 |
neighbourhood | 0.000000 | 0.000000 |
latitude | 0.000000 | 0.000000 |
longitude | 0.000000 | 0.000000 |
room_type | 0.000000 | 0.000000 |
price | 0.000000 | 0.000000 |
minimum_nights | 0.000000 | 0.000000 |
number_of_reviews | 0.000000 | 0.000000 |
last_review | 0.251767 | 0.356240 |
reviews_per_month | 0.251767 | 0.356240 |
calculated_host_listings_count | 0.000000 | 0.000000 |
availability_365 | 0.000000 | 0.000000 |
number_of_reviews_ltm | 0.000000 | 0.000000 |
license | 1000000 | 1000000 |
É muito importante fazermos a limpeza desses dados ausentes e deixar apenas valores que serão úteis.
Como as variáveis name e host_name, possuem um percentual baixo de valores ausentes, nós iremos eliminar essas linhas, já que não irá interferir na análise. E para isso iremos criar um novo dataframe com os nomes de dfNY_clean (dados limpos do New York) e dfRJ_clean (dados limpos do Rio de Janeiro).
In [9]:
dfNY_clean = dfNY.dropna(subset=['name', 'host_name'], axis=0)
dfRJ_clean = dfRJ.dropna(subset=['name', 'host_name'], axis=0)
Já para o reviews_per_month e last_review, o percentual de valores ausentes é alto e com certeza eliminar eles impactaria nos resultados. Por esse fator iremos substituir os valores ausentes pela mediana de cada variável.
In [10]:
#reviews per month NY
rpm_ny_median = dfNY_clean.reviews_per_month.median()
dfNY_clean = dfNY_clean.fillna({"reviews_per_month": rpm_ny_median})
#last_review NY
lr_ny_median = dfNY_clean['last_review'].astype('datetime64[ns]').quantile(0.5, interpolation="midpoint")
dfNY_clean = dfNY_clean.fillna({"last_review": lr_ny_median})
#reviews per mouth RJ
rpm_rj_median = dfRJ_clean.reviews_per_month.median()
dfRJ_clean = dfRJ_clean.fillna({"reviews_per_month": rpm_rj_median})
#last review RJ
lr_rj_median = dfRJ_clean['last_review'].astype('datetime64[ns]').quantile(0.5, interpolation="midpoint")
dfRJ_clean = dfRJ_clean.fillna({"last_review": lr_ny_median})
Quando falamos de distribuição de variáveis, temos sempre o objetivo de identificar outliers (ou Pontos discrepantes), que são dados que se diferenciam drasticamente de todos os outros. Em outras palavras, um outlier é um valor que foge da normalidade e que pode causar anomalias nos resultados obtidos, como subir excessivamente o valor da média aritmética de um conjunto de dados.
E para identificarmos os outliers, iremos plotar o gráfico de boxplot, para poder observar a distribuição dos valores.
Iremos analisar o price e o minimum_nights, já que essas duas variáveis são as mais importantes a serem observadas.
In [11]:
dx0 = ['price', 'minimum_nights']
for n in dx0:
data_a = dfNY_clean[n]
data_b = dfRJ_clean[n]
data_2d=[data_a,data_b]
plt.boxplot(data_2d, vert=False, labels=["New York", "Rio de Janeiro"])
plt.title(n)
plt.show()
Out [11]:
O aviso que aparece na hora de plotar o boxplot é originado pelo fato do dataframe do New York ser maior (quantidade de entradas) que o do Rio de Janeiro, criando uma sinalização de alerta, mas não quer dizer que há um erro, já que a função plt.boxplot da ênfase em usar sempre a mesma quantidade de dados para comparar.
Note que para ambas as variáveis e dataframes existem valores discrepantes, é um pouco óbvio notar que não existe realmente um imóvel que possua um price (preço) de R$ 600.000 por noite no Rio de Janeiro, provavelmente é um erro de cadastro ou do sistema.
Isso ocorre também com o minimum_nights, pois é quase improvável existir ofertas de imóveis onde o usuário tenha que ficar no mínimo 3 anos hospedado.
Esses valores (outliers) interferem na média e desvio padrão da amostra, deixando mais complicado identificar um padrão ou tirar uma informação relevante.
Existem alguns métodos para remover os outliers, como o métodos baseados em distância e o baseado no desvio padrão, entre outros.
Vamos utilizar o conceito do boxplot, uma técnica mais genérica, que identifica outliers todos os pontos que estão fora dos quartis superior e inferior [25% – 75%]. Só lembrando que esse não é o método mais eficiente.
Mas para dar início precisamos analisar os dados estatísticos, como a média, desvio padrão, mediana e seus 1° e 3° quartil. Utilizando o comando describe().
In [12]:
# New York
dfNY_clean[['price', 'minimum_nights', 'number_of_reviews', 'reviews_per_month', 'calculated_host_listings_count', 'availability_365']].describe()
# Rio de Janeiro
dfRJ_clean[['price', 'minimum_nights', 'number_of_reviews', 'reviews_per_month', 'calculated_host_listings_count', 'availability_365']].describe()
Out [12]:
New York
price | minimum_nights | number_of_reviews | reviews_per_month | calculated_host_listings_count | availability_365 | |
---|---|---|---|---|---|---|
count | 36799000000 | 36799000000 | 36799000000 | 36799000000 | 36799000000 | 36799000000 |
mean | 601688656 | 22130112 | 23047827 | 1199789 | 13442920 | 123594255 |
std | 1100769739 | 27943759 | 49455410 | 3534317 | 45067787 | 138273265 |
min | 0.000000 | 1000000 | 0.000000 | 0.010000 | 1000000 | 0.000000 |
0.25 | 200000000 | 3000000 | 1000000 | 0.180000 | 1000000 | 0.000000 |
0.5 | 393000000 | 30000000 | 4000000 | 0.440000 | 1000000 | 61000000 |
0.75 | 706464000 | 30000000 | 20000000 | 1000000 | 3000000 | 264000000 |
max | 53520000000 | 1250000000 | 1006000000 | 163190000 | 307000000 | 365000000 |
Rio de Janeiro
price | minimum_nights | number_of_reviews | reviews_per_month | calculated_host_listings_count | availability_365 | |
---|---|---|---|---|---|---|
count | 23375000000 | 23375000000 | 23375000000 | 23375000000 | 23375000000 | 23375000000 |
mean | 711739594 | 5283209 | 14095786 | 0.515049 | 7236791 | 229120171 |
std | 4939632466 | 20863285 | 33284845 | 0.751142 | 21707342 | 130198335 |
min | 0.000000 | 1000000 | 0.000000 | 0.010000 | 1000000 | 0.000000 |
0.25 | 150000000 | 1000000 | 0.000000 | 0.160000 | 1000000 | 90000000 |
0.5 | 270000000 | 2000000 | 2000000 | 0.270000 | 1000000 | 264000000 |
0.75 | 548000000 | 4000000 | 11000000 | 0.480000 | 3000000 | 362000000 |
max | 621850000000 | 1000000000 | 486000000 | 25520000 | 187000000 | 365000000 |
Observando os dados podemos confirmar algumas hipóteses:
Agora que confirmamos quais os valores acima dos limites do 3° quartil, iremos removê-los. Vamos também arredondar para cima esse valor, com o intuito de garantir que apareça bem o limite superior do nosso boxplot. Só dando ênfase, estamos apenas analisando o price e o minimum_nigths.
Para fazer essa limpeza, iremos criar um novo dataframe o dfNY_out (dados sem outliers New York) e o dfRJ_out (dados sem outliers Rio de Janeiro).
In [13]:
# New York
dfNY_out = dfNY_clean.copy()
dfNY_out.drop(dfNY_out[dfNY_out.price > 1100].index, axis=0, inplace=True)
dfNY_out.drop(dfNY_out[dfNY_out.minimum_nights > 65].index, axis=0, inplace=True)
# Rio de Janeiro
dfRJ_out = dfRJ_clean.copy()
dfRJ_out.drop(dfRJ_out[dfRJ_out.price > 600].index, axis=0, inplace=True)
dfRJ_out.drop(dfRJ_out[dfRJ_out.minimum_nights > 4].index, axis=0, inplace=True)
Basta agora reproduzir o boxplot como o anterior, mas desta vez utilizando os novos dataframes {cod [11]}. E vamos ver claramente que não haverá pontos discrepantes.
Out [14]:
Feito tudo isso, agora podemos ter uma visão mais clara dos nossos dados e enfim fazer um comparativo entre New York e Rio de Janeiro. Para esse propósito, iremos analisar a distribuição através de um histograma.
In [15]:
dx = ['price', 'minimum_nights', 'number_of_reviews', 'reviews_per_month',
'calculated_host_listings_count', 'availability_365']
for n in dx:
if dfNY_out[n].max() >= dfRJ_out[n].max():
maior = int(dfNY_out[n].max())
else:
maior = int(dfRJ_out[n].max())
bins = np.linspace(0, maior, 15)
pyplot.hist(dfRJ_out[n], bins, alpha=0.5, label='Rio de Janeiro')
pyplot.hist(dfNY_out[n], bins, alpha=0.5, label='New York')
pyplot.legend(loc='upper right')
pyplot.title(n
pyplot.show()
Out [15]:
Esse é o momento mais aguardado, analisar os resultados. Não vamos gerar no primeiro momento insights, apenas constatar alguns números. Então bora lá.
Estudar a correlação que existe entre as variáveis pode ser muito útil, se identificado algum fator. A correlação mede a direção e o grau de associação linear entre as variáveis, ou seja, quando uma variável pode influenciar outra. E para interpretar os dados gerados na correlação, precisamos saber.
Para gerar a correlação usamos a função corr() e para plotar um mapa de calor usamos a função sns.heatmap(). Vamos começar por New York.
In [16]:
corr = dfNY_out[['price', 'minimum_nights', 'number_of_reviews', 'reviews_per_month',
'calculated_host_listings_count', 'availability_365']].corr()
sns.heatmap(corr, cmap='RdBu', fmt='.2f', square=True, linecolor='white', annot=True);
Out [16]:
Iremos repetir o processo {cod [16}, mas desta vez vamos usar o dataframe do Rio de Janeiro
Out [17]:
As correlações não apresentaram muita intensidade, com exceção as variaveis number_of_reviews e reviews_per_month, que na qual é o mesmo valor, só que uma delas tem uma relação com o tempo. Nada que não nos surpreendesse.
Quando falamos em compreender as características do mercado hoteleiro de ambas as cidades, precisamos entender quais os tipos de imóveis mais ofertados.
O Airbnb classifica seus imóveis em 4 categorias (room_type), na qual o anfitrião deve escolher, para disponibilizar aos usuários, são eles:
Para gerar esse comparativo, vamos fazer ele em duas etapas, a primeira é criar uma lista com o percentual de cada categoria para cada dataframe. E após isso, criaremos um histograma horizontal e colocaremos lado a lado cada cidade com seus respectivos percentuais de cada tipo de imóvel ofertado.
In [18]:
var = ['Entire home/apt',
'Private room',
'Shared room',
'Hotel room']
dado_var = {}
for i in var:
dado_var[i] = [dfNY_out.loc[dfNY_out.room_type == i].shape[0] / dfNY_out.room_type.shape[0] , dfRJ_out.loc[dfRJ_out.room_type == i].shape[0] / dfRJ_out.room_type.shape[0]]
ima = pd.DataFrame(dado_var, index=['New York', 'Rio de Janeiro'])
ima.plot(kind="barh",stacked=True,figsize=(6,4), color=['c', 'm', 'y', 'orange'])
plt.legend(loc="lower left",bbox_to_anchor=(0.8,1.0))
plt.show()
Out [18]:
Fica claro entender que New York tem uma disponibilidade dos tipos imóveis bem equiparadas entre o modelo Entire home/apte e o private room, chegando a um percentual próximo de 50% cada.
Já no Rio de Janeiro, nota-se que a disponibilidade é maior para Entire home/apt (67,6%).
Entender a importância da localização na valorização do imóvel é um fator que contribui muito na recorrência do aluguel e na lucratividade do mesmo. Para especialistas imobiliários, o valor de um imóvel está ligado a:
Mesmo sendo um especialista não é nada fácil precificar. Mas podemos chegar bem próximo de entendermos os valores que já são negociados no momento.
New York
Para isso vamos ver a média dos valores comercializados em cada bairro e ordenar por ordem decrescente, do mais caro para o mais barato.
In [19]:
dfNY_out.groupby(['neighbourhood']).price.mean().sort_values(ascending=False)[:10]
Out [19]:
neighbourhood
Neponsit 1070.40
Belle Harbor 984.34
Fort Wadsworth 800.00
Lighthouse Hill 773.25
Dongan Hills 752.03
Howland Hook 741.25
Oakwood 665.36
Breezy Point 642.15
Douglaston 638.67
Grymes Hill 637.52
Name: price, dtype: float64
O nosso dataframe possui a variável neighbourhood.group, utilizando ela vamos conseguir ter uma visão mais abrangente, realista e entregando de uma forma que qualquer leigo em New York consegue entender. Por exemplo, muito mais pessoas entende o que é Manhattan, Queens e Brooklyn do que a diferença entre Flushing, Astoria, Hell’s Kitchen e Tribecca.
In [20]:
dfNY_out.groupby(['neighbourhood_group']).price.mean().sort_values(ascending=False)[:10]
Out [20]:
neighbourhood_group
Manhattan 444.00
Staten Island 425.03
Brooklyn 389.08
Bronx 337.36
Queens 334.24
Name: price, dtype: float64
Observe que a diferença não é tão grande entre Belle Harbor, Gerritsen Beach e Neposit que são os bairros mais caros.
Tirando o fato que os três estão bem próximos um do outro e localizado perto Marine Parkway Bridge. Todas elas possuem poucos imóveis para serem locados, assim gerando um preço mais elevado, “relação demanda e oferta”.
Outro aspecto a se observar é fazermos uma correlação visual (mapa de calor) entre a localização geográfica versus preço. Mas para fazer um gráfico bonito, vamos usar o Folium, que é um pacote que permite a visualização de dados em um mapa de folheto interativo.
Para podermos utilizar o folium com mais performance, introduziremos os primeiros 16 mil dados do dataframe, pois valores acima dessa quantidade irão acarretar sobrecarga no processamento, não gerando a visualização do gráfico. E também utilizaremos o pacote branco, para criar uma legenda dos valores de preços em relação a tonalidade de cores em nosso mapa.
In [21]:
import folium
import branca
colormap = branca.colormap.linear.YlOrRd_09.scale(0, 1100)
colormap = colormap.to_step(index = [0, 275, 550, 825, 1100])
colormap.caption = 'Preços dos imóveis'
m = folium.Map(location=[40.691895, -73.902734], tiles="stamentoner", zoom_start=11)
lon = []
lat = []
value = []
data= {'lon': lon, 'lat': lat, 'value': value}
for n in range(0, dfNY_out.shape[0]):
lon.append(dfNY_out.longitude.values[n])
lat.append(dfNY_out.latitude.values[n])
value.append(dfNY_out.price.values[n])
for i in range(0, 16000):
preco = data['value'][i]
if preco <= 275:
print = '#f1f8d0'
elif preco > 275 and preco <= 550:
print = '#efc271'
elif preco > 825 and preco <= 1100:
print = '#e35d4d'
else:
print = '#8b2a40'
folium.CircleMarker(
location=[data['lat'][i], data['lon'][i]],
radius= 2,
popup='Laurelhurst Park',
color= print,
line_color= print,
fill_color=print,
fill=True).add_to(m)
colormap.add_to(m)
m
Out [21]:
E analisando o nosso mapa e o neighbourhood.group, identificamos que há uma alta demanda em Manhattan, sendo seus preços e quantidade de ofertas um pouco mais altos quando comparado a outros distritos.
Não é à toa que Manhattan é a menina dos olhos de New York. É um dos lugares mais lindos do mundo, lá você encontra o Central Park, a Times Square, o Empire State Building e os grandes arranha-céus.
Ao sul de Manhattan está localizado o maior centro financeiro do mundo, que foi importante para a fundação da cidade, além de ser um dos pilares econômicos do país. Lá você pode encontrar o Wall Street, ou seja a rua onde fica localizada a bolsa de valores e outras empresas do mercado financeiro.
Rio de Janeiro
Agora vamos reproduzir os mesmos passos anteriores do neibourhood mas com os dados do Rio de Janeiro {Cod [19]}.
Out [22]:
neighbourhood
Ribeira 500.00
Barros Filho 500.00
Cascadura 452.50
Pavuna 383.50
Cavalcanti 350.00
Paciência 346.00
Higienópolis 328.57
Leblon 320.05
Moneró 309.00
Manguinhos 300.00
Name: price, dtype: float64
Os dados do Rio de Janeiro não apresentam valores na coluna do neighbourhood.group, mas isso não será problema, basta inserir eles utilizando uma condição que relacionará o nome do bairro com a zona na qual fica.
In [23]:
zona_sul = ['Botafogo', 'Catete', 'Copacabana', 'Cosme Velho', 'Flamengo', 'Gávea', 'Glória', 'Humaitá', 'Ipanema','Jardim Botânico', 'Lagoa', 'Laranjeiras', 'Leblon', 'Leme', 'São Conrado', 'Urca', 'Vidigal', 'Rocinha']
zona_norte = ['Alto da Boa Vista', 'Andaraí', 'Grajaú', 'Maracanã', 'Praça da Bandeira', 'Tijuca', 'Vila Isabel', 'Água Santa', 'Cachambi', 'Del Castilho', 'Encantado', 'Engenho de Dentro', 'Engenho Novo',
'Higienópolis', 'Jacaré', 'Jacarezinho', 'Lins de Vasconcelos', 'Manguinhos', 'Maria da Graça', 'Méier', 'Piedade', 'Pilares', 'Riachuelo', 'Rocha', 'Sampaio', 'São Francisco Xavier', 'Todos os Santos',
'Bonsucesso', 'Bancários', 'Cacuia', 'Cidade Universitária', 'Cocotá', 'Galeão', 'Jardim Carioca', 'Jardim Guanabara', 'Maré', 'Moneró', 'Olaria', 'Pitangueiras', 'Portuguesa', 'Praia da Bandeira',
'Ramos', 'Ribeira', 'Tauá', 'Zumbi', 'Acari', 'Anchieta','Barros Filho', 'Bento Ribeiro', 'Brás de Pina', 'Campinho', 'Cavalcanti', 'Cascadura', 'Coelho Neto', 'Colégio', 'Complexo do Alemão', 'Cordovil',
'Costa Barros', 'Engenheiro Leal', 'Engenho da Rainha', 'Guadalupe', 'Honório Gurgel', 'Inhaúma', 'Irajá', 'Jardim América', 'Madureira', 'Marechal Hermes', 'Oswaldo Cruz', 'Parada de Lucas', 'Parque Anchieta',
'Parque Colúmbia', 'Pavuna', 'Penha', 'Penha Circular', 'Quintino Bocaiuva', 'Ricardo de Albuquerque', 'Rocha Miranda', 'Tomás Coelho', 'Turiaçu', 'Vaz Lobo', 'Vicente de Carvalho', 'Vigário Geral',
'Vila da Penha', 'Vila Kosmos', 'Vista Alegre', 'Freguesia (Ilha)']
zona_oeste = ['Anil', 'Barra da Tijuca', 'Camorim', 'Cidade de Deus', 'Curicica', 'Freguesia (Jacarepaguá)', 'Gardênia Azul', 'Grumari', 'Itanhangá', 'Jacarepaguá', 'Joá', 'Praça Seca', 'Pechincha', 'Rio das Pedras',
'Recreio dos Bandeirantes', 'Tanque', 'Taquara', 'Vargem Grande', 'Vargem Pequena', 'Vila Valqueire', 'Jardim Sulacap','Bangu', 'Campo dos Afonsos', 'Deodoro', 'Gericinó', 'Jabour', 'Magalhães Bastos',
'Padre Miguel', 'Realengo', 'Santíssimo', 'Senador Camará', 'Vila Kennedy', 'Vila Militar','Barra de Guaratiba', 'Campo Grande', 'Cosmos', 'Guaratiba', 'Inhoaíba', 'Paciência', 'Pedra de Guaratiba', 'Santa Cruz',
'Senador Vasconcelos', 'Sepetiba']
zona_centro = ['São Cristóvão', 'Benfica', 'Caju', 'Catumbi', 'Centro', 'Cidade Nova', 'Estácio', 'Gamboa', 'Lapa', 'Mangueira', 'Paquetá', 'Rio Comprido', 'Santa Teresa', 'Santo Cristo', 'Saúde', 'Vasco da Gama']
for s in zona_sul:
dfRJ_out.neighbourhood_group = dfRJ_out.neighbourhood_group.mask(dfRJ_out.neighbourhood == s, 'Zona Sul')
for n in zona_norte:
dfRJ_out.neighbourhood_group = dfRJ_out.neighbourhood_group.mask(dfRJ_out.neighbourhood == n, 'Zona Norte')
for o in zona_oeste:
dfRJ_out.neighbourhood_group = dfRJ_out.neighbourhood_group.mask(dfRJ_out.neighbourhood == o, 'Zona Oeste')
for c in zona_centro:
dfRJ_out.neighbourhood_group = dfRJ_out.neighbourhood_group.mask(dfRJ_out.neighbourhood == c, 'Centro')
dfRJ_out.groupby(['neighbourhood_group']).price.mean().sort_values(ascending=False)[:10]
Out [23]:
neighbourhood_group
Zona Oeste 261.39
Zona Sul 247.96
Centro 187.87
Zona Norte 179.89
Name: price, dtype: float64
O Rio de Janeiro é uma cidade turística, e quando avaliamos quais os bairros mais caros, percebemos que não aparece nenhum dos mais famosos, como Copacabana, Ipanema e Leme.
Podemos atribuir ao mesmo fator que analisamos em New York, no caso, os bairros mais caros possuem entre 1 a 2 ofertas de imóveis para serem alugados, ou seja, a média dos preços dos bairros está ligado diretamente a essas poucas ofertas.
Para reproduzir o nosso mapa, usaremos o mesmo código anterior {Cod [21]}, mas além de usar o dataframe do Rio, também mudaremos as escalas [0, 150, 300, 450, 600] e o location [-22.930925, -43.414593].
Out [24]:
Um fator interessante no mapa, é que os imóveis mais próximos das praias são os que aparentam ter maior preço médio, principalmente comparado a zona norte e centro.
Vou dar destaque as praias do Leblon e Ipanema, com seus barzinhos, espaços para esportes e a vista incrível para o Morro Dois Irmãos, que por sinal quem tiver a oportunidade de visitar, vale muito a pena, um dos lugares mais lindos que já fui.
A zona Oeste podemos destacar as praias da Tijuca, que é um lugar ideal para mergulhar, surfar e passear com a família. O motivo que o torna mais caro que a zona Sul (Copacabana Leblon, Ipanema …), por exemplo, é o fato de haver mais casas do que hotéis. Pois essa relação de braço de ferro entre hotéis e o Airbnb ajuda a harmonizar os preços e deixar mais próximo da realidade para as pessoas.
Para todo o processo de análise de dados é fundamental entender e explorar os dados do dataframe, identificar os valores nulos e os outliers. São passos que nos permitiram fazer um comparativo entre New York e Rio de Janeiro.
Ambas as cidades possuem muitas semelhanças, entre tanto, alguns comportamentos (nos dados) foi notado, entre eles:
Ticket médio
O ticket médio representa o valor médio gasto nos pedidos, quanto maior for o valor, mais os clientes estão gastando nos pedidos. É o indicador usado para avaliar o comportamento e satisfação dos clientes.
In [25]:
ticktNY = ( dfNY_out.price * dfNY_out.minimum_nights ).sum() / dfNY_out.shape[0]
ticktRJ = ( dfRJ_out.price * dfRJ_out.minimum_nights ).sum() / dfRJ_out.shape[0]
New York tem um Ticket médio muito maior que o Rio de Janeiro, fato esse não apenas influenciado pelo seus preços serem maior, mas também por ter a média do mínimo de noites aproxima de 30 dias, enquanto que no Rio, varia entre é 5 dias, valores esse 6 vezes menor que New York.
Tempo de exposição do anúncio
É uma métrica de desempenho das plataformas de marketplaces, que determina o tempo que um anúncio fica exposto na plataforma. Quanto maior o tempo de exposição, mais possibilidade de engajamento e conversão
É fácil notar que no Rio de Janeiro tem um tempo de exposição dos anúncios maior que o de New York, isso não quer dizer que o Rio converte mais clientes, mas é um indício que os anfitriões precisam deixar mais tempo o anúncio para converter. Outra hipótese é que seja um fator característico dos anfitriões, ou seja, os proprietários dos imóveis no Rio de Janeiro não moram lá, consequentemente deixam seus imóveis o ano inteiro para gerar lucratividade, e podemos embasar esse argumento pelo fato dos tipos de imóveis mais alugados no Rio ser casas ou apartamentos inteiros.
Gerando soluções
Para nós que trabalhamos com marketing, essas são informações valiosas, que nos ajudariam a desenvolver soluções para esses anfitriões, como:
Para os anfitriões do Rio de Janeiro, podemos oferecer uma solução para campanhas de marketing customizada que tenham o objetivo de aumentar a frequência de locação dos imóveis.
Já para quem é de New York, pensamos em oferecer um recurso que ajude a precificar melhor seus imóveis de acordo com a sua localização, garantindo o máximo de lucratividade versus o tempo de exposição do anúncio.
Sei que foi uma caminhada longa nesse artigo, mas esse é o trabalho de quem vê o mundo através dos dados e assim gera inteligência com uma base forte. Então, meu caro marketeiro.
Prontos para começar do zero?
Arquivo Completo no Github
Oi, sou Hyan e aqui você vai encontrar tudo sobre marketing e tecnologia, assuntos esses na qual eu me dedico a aprender e me desafiar todas as manhãs.
Airbnb • Marketing • imóveis • Analise • DataMarketing • Dados • Rio de Janeiro • New Yrok • Ausentes • Price • Mapa • Ticket médio • Anúncio
Produção: Zero.ai
Texto: Hyan Dias Tavares
Revisão: Rafael Duarte
Revisão: Sílvia B. Canever
Ilustração: Hyan Dias Tavares
Inspiração: Sigmoidal
Deixe seu comentário