Faça uma análise exploratória para avaliar a consistência dos dados e identifcar possíveis variáveis que impactam sua variável resposta.
Para a realização deste teste você pode utilizar o software de sua preferência (Python ou R).
Sua solução deverá ser entregue no formato Jupyter, por meio de um repositório Git. Inclua também um arquivo README.md no qual você deve cobrir as respostas para os 5 pontos abaixo.
a. Como foi a definição da sua estratégia de modelagem?
b. Como foi definida a função de custo utilizada?
c. Qual foi o critério utilizado na seleção do modelo final?
d. Qual foi o critério utilizado para validação do modelo? Por que escolheu utilizar esse método?
e. Quais evidências você possui de que seu modelo é suficientemente bom?
O dataset utilizado é uma extração de dados do Airbnb Rio de Janeiro
, conforme
fonte.
Airbnb
permite aos indivíduos alugar o todo ou parte de sua própria casa, como uma forma de acomodação extra. O site fornece uma plataforma de busca e reservas entre a pessoa que oferece a acomodação e o turista que busca pela locação. Abrange mais de 500 mil anúncios em mais de 35.000 cidades e 192 países. Desde sua criação em Novembro de 2008 até Junho de 2012, mais de 10 milhões de reservas foram agendadas via Airbnb.
Random Forest
MSE (Mean Squared Error)
MAE (Mean Absolute Error)
R^2 (R squared)
1. Imports
1.1. Bibliotecas
1.2. Conjunto de dados
1.3. Dicionário das variáveis
2. Análise Exploratória dos dados
2.1. Descrição dos dados
2.2. Respondendo à perguntas
3. Machine Learning
3.1. Preparação dos dados
3.2. Definindo a baseline
3.3. Tranformação dos dados
3.4. Escolhendo o modelo
3.5. Variação no treino dos modelos
3.5.1. 1º Tunning do modelo selecionado
3.5.2. 2º Tunning do modelo selecionado
4. Treinamento com todos os dados
4.1. Previsão nos dados de teste
5. Conclusão
BASELINE:
MSE: 14404.359124812358
MAE: 98.5996424320113
R^2: 0.2230869229876291
MODELO FINAL:
MSE: 0.2199302824060129
MAE: 0.38104048502370497
R^2: 0.41041561263625315
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import plotly.express as px
from sklearn.model_selection import GridSearchCV
from sklearn.model_selection import train_test_split
from sklearn.model_selection import RandomizedSearchCV
from sklearn.linear_model import Ridge
from sklearn.linear_model import Lasso
from sklearn.linear_model import LinearRegression
from sklearn.tree import DecisionTreeRegressor
from sklearn.ensemble import ExtraTreesRegressor
from sklearn.ensemble import RandomForestRegressor
from sklearn.ensemble import GradientBoostingRegressor
from sklearn.svm import SVR
from lightgbm import LGBMRegressor
from sklearn.metrics import mean_squared_error
from sklearn.metrics import mean_absolute_error
from sklearn.metrics import r2_score
from sklearn.preprocessing import OneHotEncoder
from sklearn.preprocessing import StandardScaler
from sklearn.preprocessing import MinMaxScaler
from sklearn.preprocessing import LabelEncoder
from pprint import pprint
%matplotlib inline
plt.style.use('fivethirtyeight')
pd.set_option('display.max_columns', 100)
import warnings
warnings.filterwarnings("ignore")
# importando o conjunto de dados
df = pd.read_csv("../dados/listings.csv", index_col="id")
# visualizando as primeiras 5 linhas
df.head()
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 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
id | |||||||||||||||
17878 | Very Nice 2Br in Copacabana w. balcony, fast WiFi | 68997 | Matthias | NaN | Copacabana | -22.96592 | -43.17896 | Entire home/apt | 221 | 5 | 260 | 2021-02-08 | 2.01 | 1 | 304 |
24480 | Nice and cozy near Ipanema Beach | 99249 | Goya | NaN | Ipanema | -22.98570 | -43.20193 | Entire home/apt | 307 | 3 | 85 | 2018-02-14 | 0.67 | 1 | 10 |
25026 | Beautiful Modern Decorated Studio in Copa | 3746246 | Ghizlane | NaN | Copacabana | -22.97712 | -43.19045 | Entire home/apt | 160 | 7 | 238 | 2020-02-15 | 1.82 | 11 | 328 |
35636 | Cosy flat close to Ipanema beach | 153232 | Patricia | NaN | Ipanema | -22.98816 | -43.19359 | Entire home/apt | 273 | 2 | 181 | 2020-03-15 | 2.02 | 1 | 207 |
35764 | COPACABANA SEA BREEZE - RIO - 20 X Superhost | 153691 | Patricia Miranda & Paulo | NaN | Copacabana | -22.98127 | -43.19046 | Entire home/apt | 135 | 3 | 353 | 2021-02-10 | 2.79 | 1 | 101 |
# imprimindo as dimensões
print(f'Quantidade de linhas: {df.shape[0]}')
print(f'Quantidade de colunas: {df.shape[1]}')
Quantidade de linhas: 26615 Quantidade de colunas: 15
Vamos criar agora, um dataframe que nos mostra se temos valores faltando, tipo dos dados e valores unicos em cada coluna.
# criando um dataframe com dados nulos, tipo de dados e valores unicos
pd.DataFrame({'valores_nulos':np.round(df.isnull().mean(), 2),
'tipo_dados': df.dtypes,
'valores_unicos': df.nunique()})
valores_nulos | tipo_dados | valores_unicos | |
---|---|---|---|
name | 0.00 | object | 25807 |
host_id | 0.00 | int64 | 17324 |
host_name | 0.00 | object | 5145 |
neighbourhood_group | 1.00 | float64 | 0 |
neighbourhood | 0.00 | object | 151 |
latitude | 0.00 | float64 | 9873 |
longitude | 0.00 | float64 | 12257 |
room_type | 0.00 | object | 4 |
price | 0.00 | int64 | 1694 |
minimum_nights | 0.00 | int64 | 67 |
number_of_reviews | 0.00 | int64 | 268 |
last_review | 0.37 | object | 1469 |
reviews_per_month | 0.37 | float64 | 492 |
calculated_host_listings_count | 0.00 | int64 | 49 |
availability_365 | 0.00 | int64 | 366 |
Podemos ver que a variável neighbourhood_group não possui nenhum valor, enquanto que nas variáveis last_review e reviews_per_month possuem 37% de dados faltando.
Olhando as primeiras linhas e comparando com o tipo dos dados vemos que algumas variáveis estão incorretas, é o caso das variáveis host_id que é do tipo categórica e está como inteiro e a last_review que é do formato data e está como objeto, vamos fazer as devidas transformações em seguida.
E os valores únicos, bom para saber quantitativamente os valores únicos em cada amostra e ter uma idéia sobre seu tipo.
# convertendo variáveis
df['host_id'] = df.host_id.astype('category')
df['last_review'] = pd.to_datetime(df.last_review)
Já sabemos que algumas variáveis possuem dados faltando, vamos dar uma olhada visualmente o quanto representa dentro do nosso conjunto de dados.
# definindo área de plotagem
plt.figure(figsize=(12,5))
# plotando gráfico
sns.heatmap(df.isnull(), cbar=False)
plt.title('Composição do dataframe')
plt.show()
A variável neigbourhood_group pode ser removida, já as variáveis last_review e reviews_per_month vamos ver posteriormente o que podemos fazer.
Vamos dar uma olhada nas distribuições das variáveis numéricas contínuas, plotando suas densidades.
# plotando o gráfico de densidade
# definindo as colunas numéricas
columns_list = ['price', 'minimum_nights', 'number_of_reviews',
'reviews_per_month', 'calculated_host_listings_count', 'availability_365']
# criando objeto para número de linhas e colunas
nrows = 2
ncols = 3
# definindo área de plotagem
fig, ax = plt.subplots(nrows=nrows, ncols=ncols, figsize=(20,8))
fig.subplots_adjust(hspace=1, wspace=1)
# criando loop para plotagem
idx = 0
for col in columns_list:
idx += 1
plt.subplot(nrows, ncols, idx)
sns.kdeplot(df[col], shade=True)
plt.title(col, fontsize=10)
plt.tight_layout()
Vamos analisar:
Com intuito de entender um pouco melhor, vamos ver as principais estatísticas com o método describe()
do pandas.
# verificando as principais estatísticas numéricas
df[columns_list].describe()
price | minimum_nights | number_of_reviews | reviews_per_month | calculated_host_listings_count | availability_365 | |
---|---|---|---|---|---|---|
count | 26615.000000 | 26615.000000 | 26615.000000 | 16657.000000 | 26615.000000 | 26615.000000 |
mean | 742.589254 | 4.725268 | 12.146308 | 0.629190 | 9.665414 | 219.438174 |
std | 5368.868834 | 19.102522 | 29.722813 | 0.876064 | 35.942124 | 141.525405 |
min | 0.000000 | 1.000000 | 0.000000 | 0.010000 | 1.000000 | 0.000000 |
25% | 157.000000 | 1.000000 | 0.000000 | 0.090000 | 1.000000 | 88.000000 |
50% | 280.000000 | 2.000000 | 2.000000 | 0.270000 | 1.000000 | 254.000000 |
75% | 550.000000 | 4.000000 | 9.000000 | 0.850000 | 3.000000 | 363.000000 |
max | 625216.000000 | 1000.000000 | 446.000000 | 29.530000 | 295.000000 | 365.000000 |
Agora ver mais claramente a dimensão dos valores em relação suas distribuições, tomando a variável price como exemplo, 75% tem valores abaixo de 550 e seu valor máximo de 652216. Vamos tratar isso mais a frente.
Vamos dar uma olhada nas estatísticas das variáveis categóricas.
# verificando as principais estatísticas categóricas
df.describe(include='O')
name | host_name | neighbourhood | room_type | |
---|---|---|---|---|
count | 26586 | 26591 | 26615 | 26615 |
unique | 25807 | 5145 | 151 | 4 |
top | Apartamento em Copacabana | Daniel | Copacabana | Entire home/apt |
freq | 34 | 312 | 7712 | 19285 |
Vamos dar uma olhada mais uma vez nas distribuições, agora como um boxplot individualmente.
# definindo área de plotagem
fig, ax = plt.subplots(6, 1, figsize=(10,6))
# criando loop para plotagem
idx_ = 0
for i in columns_list:
idx_ += 1
plt.subplot(6, 1, idx_)
df[i].plot(kind='box', vert=False)
plt.tight_layout()
Precisamos tratar essas variáveis, porque os outliers influenciam diretamente no nosso modelo preditivo. Há várias técnicas para remover os outliers, como pelo z-score e pelo quantidade do interquartil por exemplo, mas vamos fazer algo mais simples definindo uma linha de corte pela concentração do volume de dados.
Por exemplo, a variável price concentra-se até em torno de 600, então definiremos os valores até 650. Da mesma forma definiremos para as variáveis minimum_nights e number_of_reviews.
Um ponto que devemos levar em consideração é a quantidade de amostras, quanto mais removemos, menor a quantidade para treinarmos o nosso modelo.
# reduzindo a quantidade de amostras da variável 'price'
df_mod = df[df['price'] < 600]
# reduzindo a quantidade de amostras da variável 'minimum_nights'
df_mod = df_mod[df_mod['minimum_nights'] < 8]
# reduzindo a quantidade de amostras da variável 'number_of_reviews'
df_mod = df_mod[df_mod['number_of_reviews'] < 10]
# reduzindo a quantidade de amostras da variável 'calculated_host_listings_count'
df_mod = df_mod[df_mod['calculated_host_listings_count'] < 70]
# df_mod[columns_list].describe()
# Q1 = df[columns_list].quantile(0.25)
# Q3 = df[columns_list].quantile(0.75)
# IQR = Q3 - Q1
# print(IQR)
# df_num = df[columns_list][~((df[columns_list] < (Q1 - 1.5 * IQR)) | (df[columns_list] > (Q3 + 1.5 * IQR))).any(axis=1)]
Conforme mencionei, com os cortes que fizemos, já reduzimos quase que 50% do conjunto de dados (de 26615 para 14053), optei por manter assim para não reduzirmos mais, mesmo que possa influenciar no nosso modelo.
Vamos novamente plotar os boxplots e observar o quanto melhorou em relação aos outliers.
# definindo área de plotagem
fig, ax = plt.subplots(6, 1, figsize=(10,6))
# criando loop para plotagem
idx_ = 0
for i in columns_list:
idx_ += 1
plt.subplot(6, 1, idx_)
df_mod[i].plot(kind='box', vert=False)
plt.tight_layout()
df_mod.shape
(13210, 15)
Então vamos atualizar nosso conjunto de dados, pelo nosso dataset completo vamos localizar as amostras do dataset modificado pelo índice, utilizando como parâmetro do método loc[]
.
# criando um novo objeto somente para dados numéricos
df_num = df_mod[columns_list]
# removendo os outliers do dataframe principal
df_new = df.loc[df_num.index.tolist()]
# checando a nova dimensão do dataset
df_new.shape
(13210, 15)
Aquela nossa variável sem dados, vamos removê-la.
# removendo a coluna sem dados
df_new.drop('neighbourhood_group', axis=1, inplace=True)
Com base na latitude e longitude, vamos plotar os pontos em um mapa pela biblioteca plotly
com open-street-map
, com isso poderemos interagir também, caso desejar.
# plotando o mapa
fig = px.scatter_mapbox(df_new, lat="latitude", lon="longitude", hover_name="name", color_discrete_sequence=["red"],
zoom=10, height=500)
fig.update_layout(mapbox_style="open-street-map")
fig.update_layout(margin={"r":0,"t":0,"l":0,"b":0})
fig.show()
# definindo a área de plotagem
plt.figure(figsize=(10, 8))
# plotando o gráfico
sns.heatmap(df_new.corr(), vmin=-1, vmax=1, annot=True, cmap='vlag')
plt.title('Heatmap com as correlações')
plt.show()
Podemos observar no geral que as correlações não são fortes e especificamente a latitude é o que mais relaciona com a nossa variável alvo price, que por sua se relaciona também com a longitude, fazendo sentido que é a localização.
Vamos analisar mais especificamente alguns pontos, respondendo as seguintes perguntas:
Qual a média de preços de aluguel?
Quais as regiões mais caras?
Quais os tipos de quartos mais alugados?
Como o número de locais listados e os preços dos quartos / apartamentos variam de acordo com a região?
Qual a variação de demanda ao longo do tempo?
Qual a variação do preço ao longo do tempo?
print(f'A média geral de preços é: R${df_new.price.mean():.2f}')
A média geral de preços é: R$253.02
# visualizando a média de preços por região
médias_por_região = df_new.groupby('neighbourhood')['price'].mean().sort_values(ascending=False)
médias_por_região
neighbourhood Osvaldo Cruz 400.000000 Paciência 362.400000 Jacaré 360.000000 Leblon 352.775061 Cavalcanti 350.000000 ... Ricardo de Albuquerque 73.000000 Parada de Lucas 68.333333 Ribeira 64.000000 Senador Camará 63.600000 Vigário Geral 59.000000 Name: price, Length: 142, dtype: float64
A região com a maior média é Osvaldo Cruz
e a menor média é Senador Camará
.
# agrupando por tipo mais alugados
df_new.groupby('room_type').agg({'room_type': 'count', 'price': 'mean'}).sort_values(by='price', ascending=False)
room_type | price | |
---|---|---|
room_type | ||
Entire home/apt | 8058 | 292.953835 |
Private room | 4606 | 196.796570 |
Hotel room | 51 | 174.882353 |
Shared room | 495 | 134.064646 |
A concentração dos tipos mais alugados, tanto em procura quanto por preço são de casas/apartamentos
e quartos inteiros
, os hoteis são os menos procurados.
Vou plotar um scatterplot com latitude e longitude, separando os pontos por cor para termos uma idéia da distribuição. Já vimos no mapa que a concentação maior de locais alugados são próximos as praias.
# definindo a área de plotagem
fig, ax = plt.subplots(figsize = (12,10))
# plotando o gráfico
ax = sns.scatterplot(data=df_new, y="latitude", x="longitude", hue='room_type')
ax.set_title('Mapeamento por tipo de estabelecimento')
plt.show()
Vamos calcular a correlação dos tipos diferentes de room_type com variável price.
df_dummies = pd.get_dummies(df_new['room_type'])
df_new_dummies = pd.concat([df_new['price'], df_dummies], axis=1)
# definindo a área de plotagem
plt.figure(figsize=(8, 6))
# plotando o gráfico
sns.heatmap(df_new_dummies.corr(), vmin=-1, vmax=1, annot=True, cmap='vlag')
plt.title('Heatmap com as correlações')
plt.show()
# definindo a área de plotagem
plt.figure(figsize=(15,10))
# plotando o gráfico
df_new.groupby('last_review')['name'].count().plot()
plt.title('Visualização ao longo do tempo')
plt.show()
# definindo a área de plotagem
plt.figure(figsize=(15,10))
# plotando o gráfico
df_new.groupby('last_review')['price'].mean().plot()
plt.title('Visualização ao longo do tempo')
plt.show()
Agora vamos começar a modelar para treinar o modelo para realizar as previsões dos preços.
Antes de tudo, temos um conjunto de dados no qual iremos separar 10% desse conjunto, com uma amostra aleatória para testar o modelo. Esse conjunto para teste não participará em momento algum do treinamento do modelo, será exclusivamente, após o modelo devidamente parametrizado e treinado para realizar as previsões.
Desse jeito simularemos os dados em produção que chegam para o modelo, sem o modelo ter visto.
# definindo a seed para rodar sempre os mesmos valores aleatórios
seed = 1
# separando um conjunto de dados somente para teste
df_test = df_new.sample(frac=0.1, random_state=seed)
# conjunto de dados treino e validação do modelo
df_train_val = df_new.drop(df_test.index.tolist())
print(f'Conjunto de dados para teste: {df_test.shape}')
print()
print(f'Conjunto de dados para treino e validação: {df_train_val.shape}')
Conjunto de dados para teste: (1321, 14) Conjunto de dados para treino e validação: (11889, 14)
Agora utilizaremos os dados de treino e validação para treinar, tunnar e validar o modelo.
Antes, vamos definir as variáveis que farão parte do nosso treinamento. já vimos qua as correlações em geral não são fortes, portanto vou selecionar as que eu acho mais significativas e depois vou ajustando conforme necessário.
# criando uma lista para as variáveis de entrada
feature_list = ['host_id', 'latitude', 'longitude', 'room_type', 'minimum_nights', 'number_of_reviews',
'reviews_per_month', 'calculated_host_listings_count', 'availability_365']
Agora vamos separar os dados em treino e validação para rodar alguns modelos, de forma mais simples pra ver qual o que performa melhor.
# separando o X e y
X = df_train_val[feature_list]
y = df_train_val.price
# separando em treino e validação
X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.2, random_state=seed)
# checando as dimensões
print(X_train.shape, X_val.shape, y_train.shape, y_val.shape)
(9511, 9) (2378, 9) (9511,) (2378,)
Para termos um base para comparação se o nosso modelo está melhorando conforme ajustes e o quanto ele melhorou, vamos definir uma baseline.
Utilizaremos um algoritmo de Linear regression sem transformações nos dados.
Para validação dos modelos utilizaremos 3 métricas para compare:
Antes de treinar o modelo, temos uma variável categórica que devemos transformar em numero para que o algoritmo entenda. A variável room_type será convertida e utilizaremos o LabelEncoder()
do Sklearn
.
Como uma boa prática, vamos criar cópias dos conjuntos antes das transformações.
# cópias dos conjuntos de dados
X_train_enc = X_train.copy()
X_val_enc = X_val.copy()
Vale ressaltar, que as transformações devem ser treinadas somente com os dados de treino, tipo fit_transform
e para os dados de validação, assim como de testes, somente transform
, para evitar o data lackage ou vazamento de dados.
# instanciando o algoritmo
le = LabelEncoder()
# treinando com os dados de treino
le.fit(X_train['room_type'])
# realizando as transformações
X_train_enc['room_type'] = le.transform(X_train['room_type'])
X_val_enc['room_type'] = le.transform(X_val['room_type'])
# visualizando o resultado
X_train_enc.head()
host_id | latitude | longitude | room_type | minimum_nights | number_of_reviews | reviews_per_month | calculated_host_listings_count | availability_365 | |
---|---|---|---|---|---|---|---|---|---|
id | |||||||||
22431596 | 159111483 | -23.01033 | -43.36819 | 0 | 2 | 4 | 0.12 | 1 | 2 |
30037231 | 95785079 | -22.98382 | -43.21652 | 0 | 4 | 0 | NaN | 1 | 273 |
41886580 | 331217718 | -22.94013 | -43.19094 | 0 | 2 | 0 | NaN | 1 | 363 |
47869957 | 258390952 | -22.98240 | -43.19380 | 0 | 2 | 1 | 1.00 | 1 | 180 |
47981244 | 305072898 | -22.96499 | -43.17447 | 0 | 2 | 0 | NaN | 4 | 178 |
Ainda precisamos tratar os dados ausentes da coluna reviews_per_month, para um primeiro treinameno vamos substituir por zero.
# X_train_enc['reviews_per_month'] = X_train_enc['reviews_per_month'].fillna(X_train_enc.reviews_per_month.mean())
# X_val_enc['reviews_per_month'] = X_val_enc['reviews_per_month'].fillna(X_train_enc.reviews_per_month.mean())
# preenchendo os dados nulos
X_train_enc['reviews_per_month'] = X_train_enc['reviews_per_month'].fillna(0)
X_val_enc['reviews_per_month'] = X_val_enc['reviews_per_month'].fillna(0)
# visualizando o resultado
X_train_enc.head()
host_id | latitude | longitude | room_type | minimum_nights | number_of_reviews | reviews_per_month | calculated_host_listings_count | availability_365 | |
---|---|---|---|---|---|---|---|---|---|
id | |||||||||
22431596 | 159111483 | -23.01033 | -43.36819 | 0 | 2 | 4 | 0.12 | 1 | 2 |
30037231 | 95785079 | -22.98382 | -43.21652 | 0 | 4 | 0 | 0.00 | 1 | 273 |
41886580 | 331217718 | -22.94013 | -43.19094 | 0 | 2 | 0 | 0.00 | 1 | 363 |
47869957 | 258390952 | -22.98240 | -43.19380 | 0 | 2 | 1 | 1.00 | 1 | 180 |
47981244 | 305072898 | -22.96499 | -43.17447 | 0 | 2 | 0 | 0.00 | 4 | 178 |
Agora vamos obter a baseline.
# instanciando o algoritmo
reg = LinearRegression()
# treinando com os dados que separamos
reg.fit(X_train_enc, y_train)
# realizando as previsões tanto nos dados de treino quanto no de validação
y_pred_train = reg.predict(X_train_enc)
y_pred_val = reg.predict(X_val_enc)
print(f'Previsão nos dados de TREINO:')
print('-----------------------------------------------------')
print(f'Mean Squared Error: {mean_squared_error(y_train, y_pred_train)}')
print(f'Mean Absolute Error: {mean_absolute_error(y_train, y_pred_train)}')
print(f'R2 score: {r2_score(y_train, y_pred_train)}\n')
print(f'Previsão nos dados de VALIDAÇÃO:')
print('-----------------------------------------------------')
print(f'Mean Squared Error: {mean_squared_error(y_val, y_pred_val)}')
print(f'Mean Absolute Error: {mean_absolute_error(y_train, y_pred_train)}')
print(f'R2 score: {r2_score(y_val, y_pred_val)}')
Previsão nos dados de TREINO: ----------------------------------------------------- Mean Squared Error: 14819.67487641476 Mean Absolute Error: 98.59964243201084 R2 score: 0.2180411679585168 Previsão nos dados de VALIDAÇÃO: ----------------------------------------------------- Mean Squared Error: 14404.359124812361 Mean Absolute Error: 98.59964243201084 R2 score: 0.2230869229876289
Nosso modelo não performou muito bem, tanto para a previsão dos dados treino quanto para validação, o modelo errou muito, mas vamos melhorar isso!
Vamos então rodar com os mesmos dados, vários algoritmos de Regressão Linear e analisar quem obtem os melhores resultados.
# instanciando os modelos
dtr = DecisionTreeRegressor()
rfr = RandomForestRegressor(n_estimators=1000)
svr = SVR()
LGBM = LGBMRegressor(n_estimators=1000)
ridge = Ridge(alpha=0.1)
lasso = Lasso(alpha=0.1)
gbr = GradientBoostingRegressor(random_state=seed)
etr = ExtraTreesRegressor(n_estimators=1000, random_state=0)
# criando uma lista de tuplas com o nome e modelo treinado
models = [('DECISION TREE', dtr),
('RANDOM FOREST', rfr),
('LGBM', LGBM),
('SVR', svr),
('RIDGE', ridge),
('LASSO', lasso),
('GRADIENT BOOSTING', gbr),
('EXTRA TREES', etr)]
# rodando o loop para obter os resultados
for name, model in models:
model.fit(X_train_enc, y_train)
y_pred_train = model.predict(X_train_enc)
y_pred_val = model.predict(X_val_enc)
print(f'{name}')
print(f'Previsão nos dados de TREINO:')
print('-----------------------------------------------------')
print(f'Mean Squared Error: {mean_squared_error(y_train, y_pred_train)}')
print(f'Mean Absolute Error: {mean_absolute_error(y_train, y_pred_train)}')
print(f'R2 score: {r2_score(y_train, y_pred_train)}\n')
print(f'Previsão nos dados de VALIDAÇÃO:')
print('-----------------------------------------------------')
print(f'Mean Squared Error: {mean_squared_error(y_val, y_pred_val)}')
print(f'Mean Absolute Error: {mean_absolute_error(y_val, y_pred_val)}')
print(f'R2 score: {r2_score(y_val, y_pred_val)}')
print()
print()
DECISION TREE Previsão nos dados de TREINO: ----------------------------------------------------- Mean Squared Error: 0.09930606665965724 Mean Absolute Error: 0.005993060666596573 R2 score: 0.9999947601241899 Previsão nos dados de VALIDAÇÃO: ----------------------------------------------------- Mean Squared Error: 26116.913372582003 Mean Absolute Error: 122.00925147182507 R2 score: -0.40864104779271404 RANDOM FOREST Previsão nos dados de TREINO: ----------------------------------------------------- Mean Squared Error: 1800.213836415492 Mean Absolute Error: 33.51188945106168 R2 score: 0.9050118763948936 Previsão nos dados de VALIDAÇÃO: ----------------------------------------------------- Mean Squared Error: 13160.326616029108 Mean Absolute Error: 91.52778640714486 R2 score: 0.2901850226620083 LGBM Previsão nos dados de TREINO: ----------------------------------------------------- Mean Squared Error: 3616.3582775409677 Mean Absolute Error: 45.02322149073394 R2 score: 0.80918317584349 Previsão nos dados de VALIDAÇÃO: ----------------------------------------------------- Mean Squared Error: 14722.875669900033 Mean Absolute Error: 96.05600250219088 R2 score: 0.20590742426927577 SVR Previsão nos dados de TREINO: ----------------------------------------------------- Mean Squared Error: 19290.483341655086 Mean Absolute Error: 111.62023707493236 R2 score: -0.017860644659808855 Previsão nos dados de VALIDAÇÃO: ----------------------------------------------------- Mean Squared Error: 18777.02849525946 Mean Absolute Error: 109.24228945778292 R2 score: -0.012757239596456582 RIDGE Previsão nos dados de TREINO: ----------------------------------------------------- Mean Squared Error: 14819.724459324427 Mean Absolute Error: 98.60497226101666 R2 score: 0.21803855172068054 Previsão nos dados de VALIDAÇÃO: ----------------------------------------------------- Mean Squared Error: 14403.650233789693 Mean Absolute Error: 97.21722227822578 R2 score: 0.22312515771233388 LASSO Previsão nos dados de TREINO: ----------------------------------------------------- Mean Squared Error: 14827.994789963914 Mean Absolute Error: 98.71073082800399 R2 score: 0.21760216845712177 Previsão nos dados de VALIDAÇÃO: ----------------------------------------------------- Mean Squared Error: 14403.045027810394 Mean Absolute Error: 97.24333733074832 R2 score: 0.22315780008368324 GRADIENT BOOSTING Previsão nos dados de TREINO: ----------------------------------------------------- Mean Squared Error: 12474.252681280748 Mean Absolute Error: 89.46085881995478 R2 score: 0.34179716231369517 Previsão nos dados de VALIDAÇÃO: ----------------------------------------------------- Mean Squared Error: 13226.231079782781 Mean Absolute Error: 92.35964714271402 R2 score: 0.2866304015032288 EXTRA TREES Previsão nos dados de TREINO: ----------------------------------------------------- Mean Squared Error: 0.10689368604773423 Mean Absolute Error: 0.009850909473241567 R2 score: 0.999994359764125 Previsão nos dados de VALIDAÇÃO: ----------------------------------------------------- Mean Squared Error: 13585.775436440706 Mean Absolute Error: 92.47108242220354 R2 score: 0.2672380279839952
Podemos ver que os algoritmos de RANDOM FOREST e GRADIENT BOOSTING foram os que obtiveram os melhores desempenhos. Vamos dar uma olhada nas features mais importantes consideradas pelos modelos.
# lista das variáveis
features = feature_list
# variáveis mais importantes pela Random Forest
importances = rfr.feature_importances_
# capturando os indices
indices = np.argsort(importances)
# plotando o gráfico
plt.barh(range(len(indices)), importances[indices], color='b', align='center')
plt.title('Feature Importances - Random Forest')
plt.yticks(range(len(indices)), [features[i] for i in indices])
plt.xlabel('Relative Importance')
plt.show()
# lista das variáveis
features = feature_list
# variáveis mais importantes pela Random Forest
importances = gbr.feature_importances_
# capturando os indices
indices = np.argsort(importances)
# plotando o gráfico
plt.barh(range(len(indices)), importances[indices], color='b', align='center')
plt.title('Feature Importances - Gradient Boosting')
plt.yticks(range(len(indices)), [features[i] for i in indices])
plt.xlabel('Relative Importance')
plt.show()
Podemos observar que, embora a ordenação sendo diferentes, analisando as 5 primeiras variáveis, vemos que os dois consideraram as mesmas.
Vou então testar outras combinações, somente para esses dois modelos, seguindo o mesmo fluxo que anteriormente.
Desconsiderando as duas últimas variáveis: minimum_nights e number_of_reviews.
Vamos analisar também com o framework boruta
.
Referência para o Boruta:
https://towardsdatascience.com/boruta-explained-the-way-i-wish-someone-explained-it-to-me-4489d70e154a
from boruta import BorutaPy
boruta = BorutaPy(
estimator = rfr,
n_estimators = 'auto',
max_iter = 100 # number of trials to perform
)
### fit Boruta (it accepts np.array, not pd.DataFrame)
boruta.fit(np.array(X_train_enc), np.array(y_train))
### print results
green_area = X.columns[boruta.support_].to_list()
blue_area = X.columns[boruta.support_weak_].to_list()
print('features in the green area:', green_area) # the features that are here are considered as predictive, so they are kept
print('features in the blue area:', blue_area) # Boruta is indecisive about the features that are in this area;
features in the green area: ['host_id', 'latitude', 'longitude', 'room_type', 'reviews_per_month'] features in the blue area: []
boruta = BorutaPy(
estimator = gbr,
n_estimators = 'auto',
max_iter = 100 # number of trials to perform
)
### fit Boruta (it accepts np.array, not pd.DataFrame)
boruta.fit(np.array(X_train_enc), np.array(y_train))
### print results
green_area = X.columns[boruta.support_].to_list()
blue_area = X.columns[boruta.support_weak_].to_list()
print('features in the green area:', green_area) # the features that are here are considered as predictive, so they are kept
print('features in the blue area:', blue_area) # Boruta is indecisive about the features that are in this area;
features in the green area: ['host_id', 'latitude', 'longitude', 'room_type', 'reviews_per_month', 'calculated_host_listings_count', 'availability_365'] features in the blue area: ['minimum_nights']
# criando uma lista para as variáveis de entrada
feature_list = ['host_id', 'latitude', 'longitude', 'room_type', 'reviews_per_month']
# separando o X e y
X = df_train_val[feature_list]
y = df_train_val.price
# separando em treino e validação
X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.2, random_state=seed)
# # checando as dimensões
# print(X_train.shape, X_val.shape, y_train.shape, y_val.shape)
# cópias dos conjuntos de dados
X_train_enc = X_train.copy()
X_val_enc = X_val.copy()
# instanciando o algoritmo
le = LabelEncoder()
# treinando com os dados de treino
le.fit(X_train['room_type'])
# realizando as transformações
X_train_enc['room_type'] = le.transform(X_train['room_type'])
X_val_enc['room_type'] = le.transform(X_val['room_type'])
# preenchendo os dados nulos
X_train_enc['reviews_per_month'] = X_train_enc['reviews_per_month'].fillna(0)
X_val_enc['reviews_per_month'] = X_val_enc['reviews_per_month'].fillna(0)
# visualizando o resultado
X_train_enc.head()
host_id | latitude | longitude | room_type | reviews_per_month | |
---|---|---|---|---|---|
id | |||||
22431596 | 159111483 | -23.01033 | -43.36819 | 0 | 0.12 |
30037231 | 95785079 | -22.98382 | -43.21652 | 0 | 0.00 |
41886580 | 331217718 | -22.94013 | -43.19094 | 0 | 0.00 |
47869957 | 258390952 | -22.98240 | -43.19380 | 0 | 1.00 |
47981244 | 305072898 | -22.96499 | -43.17447 | 0 | 0.00 |
# instanciando os modelos
rfr = RandomForestRegressor(n_estimators=1000)
gbr = GradientBoostingRegressor(random_state=seed)
# criando uma lista de tuplas com o nome e modelo treinado
models = [('RANDOM FOREST', rfr),
('GRADIENT BOOSTING', gbr)]
# rodando o loop para obter os resultados
for name, model in models:
model.fit(X_train_enc, y_train)
y_pred_train = model.predict(X_train_enc)
y_pred_val = model.predict(X_val_enc)
print(f'{name}')
print(f'Previsão nos dados de TREINO:')
print('-----------------------------------------------------')
print(f'Mean Squared Error: {mean_squared_error(y_train, y_pred_train)}')
print(f'Mean Absolute Error: {mean_absolute_error(y_train, y_pred_train)}')
print(f'R2 score: {r2_score(y_train, y_pred_train)}\n')
print(f'Previsão nos dados de VALIDAÇÃO:')
print('-----------------------------------------------------')
print(f'Mean Squared Error: {mean_squared_error(y_val, y_pred_val)}')
print(f'Mean Absolute Error: {mean_absolute_error(y_val, y_pred_val)}')
print(f'R2 score: {r2_score(y_val, y_pred_val)}')
print()
print()
RANDOM FOREST Previsão nos dados de TREINO: ----------------------------------------------------- Mean Squared Error: 1899.7724113833406 Mean Absolute Error: 34.34217594918895 R2 score: 0.8997586770061896 Previsão nos dados de VALIDAÇÃO: ----------------------------------------------------- Mean Squared Error: 13734.898749123635 Mean Absolute Error: 93.24124528091173 R2 score: 0.2591949175125823 GRADIENT BOOSTING Previsão nos dados de TREINO: ----------------------------------------------------- Mean Squared Error: 12865.16203398279 Mean Absolute Error: 90.96550459690985 R2 score: 0.3211708649473841 Previsão nos dados de VALIDAÇÃO: ----------------------------------------------------- Mean Squared Error: 13599.108298675372 Mean Absolute Error: 93.82341955791867 R2 score: 0.2665189071307619
# criando uma lista para as variáveis de entrada
feature_list = ['host_id', 'latitude', 'longitude', 'room_type', 'reviews_per_month']
# separando o X e y
X = df_train_val[feature_list]
y = df_train_val.price
# separando em treino e validação
X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.2, random_state=seed)
# # checando as dimensões
# print(X_train.shape, X_val.shape, y_train.shape, y_val.shape)
# cópias dos conjuntos de dados
X_train_enc = X_train.copy()
X_val_enc = X_val.copy()
# instanciando o algoritmo
le = LabelEncoder()
# treinando com os dados de treino
le.fit(X_train['room_type'])
# realizando as transformações
X_train_enc['room_type'] = le.transform(X_train['room_type'])
X_val_enc['room_type'] = le.transform(X_val['room_type'])
# preenchendo os dados nulos
X_train_enc['reviews_per_month'] = X_train_enc['reviews_per_month'].fillna(X_train_enc.reviews_per_month.mean())
X_val_enc['reviews_per_month'] = X_val_enc['reviews_per_month'].fillna(X_train_enc.reviews_per_month.mean())
scaler = StandardScaler()
scaler.fit(X_train_enc)
X_train_enc = scaler.transform(X_train_enc)
X_val_enc = scaler.transform(X_val_enc)
# y_log = np.log1p(y)
# visualizando o resultado
pd.DataFrame(X_train_enc, columns=feature_list)
host_id | latitude | longitude | room_type | reviews_per_month | |
---|---|---|---|---|---|
0 | 0.346405 | -1.337315 | -1.236622 | -0.789081 | -0.507305 |
1 | -0.193883 | -0.628084 | 0.318753 | -0.789081 | 0.000000 |
2 | 1.814779 | 0.540770 | 0.581075 | -0.789081 | 0.000000 |
3 | 1.193436 | -0.590094 | 0.551746 | -0.789081 | 1.392077 |
4 | 1.591717 | -0.124318 | 0.749975 | -0.789081 | 0.000000 |
... | ... | ... | ... | ... | ... |
9506 | -0.895237 | -0.053957 | 0.845039 | -0.789081 | 2.643943 |
9507 | -0.538988 | 0.049311 | 0.498420 | 1.133786 | 0.000000 |
9508 | -0.849474 | -0.180768 | 0.703315 | 1.133786 | -0.658393 |
9509 | -0.360920 | 1.377882 | 0.550003 | 1.133786 | 0.000000 |
9510 | -0.948810 | 1.641670 | 0.183284 | -0.789081 | 0.000000 |
9511 rows × 5 columns
# instanciando os modelos
rfr = RandomForestRegressor(n_estimators=1000)
gbr = GradientBoostingRegressor(random_state=seed)
# criando uma lista de tuplas com o nome e modelo treinado
models = [('RANDOM FOREST', rfr),
('GRADIENT BOOSTING', gbr)]
# rodando o loop para obter os resultados
for name, model in models:
model.fit(X_train_enc, y_train)
y_pred_train = model.predict(X_train_enc)
y_pred_val = model.predict(X_val_enc)
print(f'{name}')
print(f'Previsão nos dados de TREINO:')
print('-----------------------------------------------------')
print(f'Mean Squared Error: {mean_squared_error(y_train, y_pred_train)}')
print(f'Mean Absolute Error: {mean_absolute_error(y_train, y_pred_train)}')
print(f'R2 score: {r2_score(y_train, y_pred_train)}\n')
print(f'Previsão nos dados de VALIDAÇÃO:')
print('-----------------------------------------------------')
print(f'Mean Squared Error: {mean_squared_error(y_val, y_pred_val)}')
print(f'Mean Absolute Error: {mean_absolute_error(y_val, y_pred_val)}')
print(f'R2 score: {r2_score(y_val, y_pred_val)}')
print()
print()
RANDOM FOREST Previsão nos dados de TREINO: ----------------------------------------------------- Mean Squared Error: 1908.7631631741406 Mean Absolute Error: 34.40932582131649 R2 score: 0.8992842807844008 Previsão nos dados de VALIDAÇÃO: ----------------------------------------------------- Mean Squared Error: 13701.754212243062 Mean Absolute Error: 93.15246620237416 R2 score: 0.2609826002488227 GRADIENT BOOSTING Previsão nos dados de TREINO: ----------------------------------------------------- Mean Squared Error: 13001.004970035261 Mean Absolute Error: 91.63992179956477 R2 score: 0.3140031244603285 Previsão nos dados de VALIDAÇÃO: ----------------------------------------------------- Mean Squared Error: 13613.572991945266 Mean Absolute Error: 94.09075999091648 R2 score: 0.2657387398731297
# criando uma lista para as variáveis de entrada
feature_list = ['host_id', 'latitude', 'longitude', 'room_type', 'minimum_nights', 'number_of_reviews',
'reviews_per_month', 'calculated_host_listings_count', 'availability_365']
# separando o X e y
X = df_train_val[feature_list]
y = df_train_val.price
# separando em treino e validação
X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.2, random_state=seed)
# # checando as dimensões
# print(X_train.shape, X_val.shape, y_train.shape, y_val.shape)
# cópias dos conjuntos de dados
X_train_enc = X_train.copy()
X_val_enc = X_val.copy()
# instanciando o algoritmo
le = LabelEncoder()
# treinando com os dados de treino
le.fit(X_train['room_type'])
# realizando as transformações
X_train_enc['room_type'] = le.transform(X_train['room_type'])
X_val_enc['room_type'] = le.transform(X_val['room_type'])
# preenchendo os dados nulos
X_train_enc['reviews_per_month'] = X_train_enc['reviews_per_month'].fillna(X_train_enc.reviews_per_month.mean())
X_val_enc['reviews_per_month'] = X_val_enc['reviews_per_month'].fillna(X_train_enc.reviews_per_month.mean())
scaler = StandardScaler()
scaler.fit(X_train_enc)
X_train_enc = scaler.transform(X_train_enc)
X_val_enc = scaler.transform(X_val_enc)
y_train_log = np.log1p(y_train)
y_val_log = np.log1p(y_val)
# visualizando o resultado
pd.DataFrame(X_train_enc, columns=feature_list)
host_id | latitude | longitude | room_type | minimum_nights | number_of_reviews | reviews_per_month | calculated_host_listings_count | availability_365 | |
---|---|---|---|---|---|---|---|---|---|
0 | 0.346405 | -1.337315 | -1.236622 | -0.789081 | -0.350623 | 0.777458 | -0.507305 | -0.396591 | -1.528463 |
1 | -0.193883 | -0.628084 | 0.318753 | -0.789081 | 0.927805 | -0.823062 | 0.000000 | -0.396591 | 0.369598 |
2 | 1.814779 | 0.540770 | 0.581075 | -0.789081 | -0.350623 | -0.823062 | 0.000000 | -0.396591 | 0.999950 |
3 | 1.193436 | -0.590094 | 0.551746 | -0.789081 | -0.350623 | -0.422932 | 1.392077 | -0.396591 | -0.281766 |
4 | 1.591717 | -0.124318 | 0.749975 | -0.789081 | -0.350623 | -0.823062 | 0.000000 | -0.066757 | -0.295774 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
9506 | -0.895237 | -0.053957 | 0.845039 | -0.789081 | -0.989837 | 2.778108 | 2.643943 | 5.980192 | -0.673986 |
9507 | -0.538988 | 0.049311 | 0.498420 | 1.133786 | 1.567019 | -0.823062 | 0.000000 | -0.396591 | -0.645970 |
9508 | -0.849474 | -0.180768 | 0.703315 | 1.133786 | 1.567019 | 0.377328 | -0.658393 | -0.176702 | 1.013958 |
9509 | -0.360920 | 1.377882 | 0.550003 | 1.133786 | 0.927805 | -0.823062 | 0.000000 | -0.176702 | 1.013958 |
9510 | -0.948810 | 1.641670 | 0.183284 | -0.789081 | -0.989837 | -0.823062 | 0.000000 | -0.396591 | 0.992946 |
9511 rows × 9 columns
# instanciando os modelos
rfr = RandomForestRegressor(n_estimators=1000)
gbr = GradientBoostingRegressor(random_state=seed)
# criando uma lista de tuplas com o nome e modelo treinado
models = [('RANDOM FOREST', rfr),
('GRADIENT BOOSTING', gbr)]
# rodando o loop para obter os resultados
for name, model in models:
model.fit(X_train_enc, y_train_log)
y_pred_train = model.predict(X_train_enc)
y_pred_val = model.predict(X_val_enc)
print(f'{name}')
print(f'Previsão nos dados de TREINO:')
print('-----------------------------------------------------')
print(f'Mean Squared Error: {mean_squared_error(y_train_log, y_pred_train)}')
print(f'Mean Absolute Error: {mean_absolute_error(y_train_log, y_pred_train)}')
print(f'R2 score: {r2_score(y_train_log, y_pred_train)}\n')
print(f'Previsão nos dados de VALIDAÇÃO:')
print('-----------------------------------------------------')
print(f'Mean Squared Error: {mean_squared_error(y_val_log, y_pred_val)}')
print(f'Mean Absolute Error: {mean_absolute_error(y_val_log, y_pred_val)}')
print(f'R2 score: {r2_score(y_val_log, y_pred_val)}')
print()
print()
RANDOM FOREST Previsão nos dados de TREINO: ----------------------------------------------------- Mean Squared Error: 0.03175201550737007 Mean Absolute Error: 0.14031220488230445 R2 score: 0.9173805517606395 Previsão nos dados de VALIDAÇÃO: ----------------------------------------------------- Mean Squared Error: 0.22932207934225063 Mean Absolute Error: 0.37983031234047554 R2 score: 0.3752814664156625 GRADIENT BOOSTING Previsão nos dados de TREINO: ----------------------------------------------------- Mean Squared Error: 0.2284675141392957 Mean Absolute Error: 0.382229487204455 R2 score: 0.4055224634661204 Previsão nos dados de VALIDAÇÃO: ----------------------------------------------------- Mean Squared Error: 0.24253539297411233 Mean Absolute Error: 0.393027608856783 R2 score: 0.3392857963102688
# criando uma lista para as variáveis de entrada
feature_list = ['host_id', 'latitude', 'longitude', 'room_type', 'minimum_nights', 'number_of_reviews',
'reviews_per_month', 'calculated_host_listings_count', 'availability_365']
# separando o X e y
X = df_train_val[feature_list]
y = df_train_val.price
# separando em treino e validação
X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.2, random_state=seed)
# # checando as dimensões
print(X_train.shape, X_val.shape, y_train.shape, y_val.shape)
(9511, 9) (2378, 9) (9511,) (2378,)
# cópias dos conjuntos de dados
X_train_enc = X_train.copy()
X_val_enc = X_val.copy()
# # Encode feature 'amenities' and concat the data
# df_roomType =X_train_enc.room_type.str.get_dummies(sep=",")
# X_train_enc = pd.concat([X_train_enc, df_roomType], axis=1).drop('room_type', axis=1)
# dfval_roomType =X_val_enc.room_type.str.get_dummies(sep=",")
# X_val_enc = pd.concat([X_val_enc, dfval_roomType], axis=1).drop('room_type', axis=1)
# instanciando o algoritmo
le = LabelEncoder()
# treinando com os dados de treino
le.fit(X_train['room_type'])
# realizando as transformações
X_train_enc['room_type'] = le.transform(X_train['room_type'])
X_val_enc['room_type'] = le.transform(X_val['room_type'])
# preenchendo os dados nulos
# X_train_enc['reviews_per_month'] = X_train_enc['reviews_per_month'].fillna(X_train_enc.reviews_per_month.mean())
# X_val_enc['reviews_per_month'] = X_val_enc['reviews_per_month'].fillna(X_train_enc.reviews_per_month.mean())
X_train_enc['reviews_per_month'] = X_train_enc['reviews_per_month'].fillna(0)
X_val_enc['reviews_per_month'] = X_val_enc['reviews_per_month'].fillna(0)
scaler = StandardScaler()
scaler.fit(X_train_enc)
X_train_enc = scaler.transform(X_train_enc)
X_val_enc = scaler.transform(X_val_enc)
y_train_log = np.log1p(y_train)
y_val_log = np.log1p(y_val)
# visualizando o resultado
X_train_enc
array([[ 0.34640477, -1.33731485, -1.23662165, ..., -0.19412377, -0.39659098, -1.52846324], [-0.19388271, -0.62808361, 0.31875278, ..., -0.43671631, -0.39659098, 0.36959772], [ 1.81477875, 0.54077012, 0.58107544, ..., -0.43671631, -0.39659098, 0.99995007], ..., [-0.84947412, -0.18076765, 0.70331492, ..., -0.33563609, -0.17670193, 1.0139579 ], [-0.36092047, 1.37788235, 0.55000281, ..., -0.43671631, -0.17670193, 1.0139579 ], [-0.94881009, 1.64167036, 0.18328435, ..., -0.43671631, -0.39659098, 0.99294616]])
# instanciando os modelos
rfr = RandomForestRegressor(n_estimators=1000)
gbr = GradientBoostingRegressor(random_state=seed)
# criando uma lista de tuplas com o nome e modelo treinado
models = [('RANDOM FOREST', rfr),
('GRADIENT BOOSTING', gbr)]
# rodando o loop para obter os resultados
for name, model in models:
model.fit(X_train_enc, y_train_log)
y_pred_train = model.predict(X_train_enc)
y_pred_val = model.predict(X_val_enc)
print(f'{name}')
print(f'Previsão nos dados de TREINO:')
print('-----------------------------------------------------')
print(f'Mean Squared Error: {mean_squared_error(y_train_log, y_pred_train)}')
print(f'Mean Absolute Error: {mean_absolute_error(y_train_log, y_pred_train)}')
print(f'R2 score: {r2_score(y_train_log, y_pred_train)}\n')
print(f'Previsão nos dados de VALIDAÇÃO:')
print('-----------------------------------------------------')
print(f'Mean Squared Error: {mean_squared_error(y_val_log, y_pred_val)}')
print(f'Mean Absolute Error: {mean_absolute_error(y_val_log, y_pred_val)}')
print(f'R2 score: {r2_score(y_val_log, y_pred_val)}')
print()
print()
RANDOM FOREST Previsão nos dados de TREINO: ----------------------------------------------------- Mean Squared Error: 0.03157922334455209 Mean Absolute Error: 0.14013145948154393 R2 score: 0.9178301607988057 Previsão nos dados de VALIDAÇÃO: ----------------------------------------------------- Mean Squared Error: 0.22879685599278685 Mean Absolute Error: 0.37874115550344084 R2 score: 0.3767122783183907 GRADIENT BOOSTING Previsão nos dados de TREINO: ----------------------------------------------------- Mean Squared Error: 0.22684167483486747 Mean Absolute Error: 0.3809180488113259 R2 score: 0.40975293337838614 Previsão nos dados de VALIDAÇÃO: ----------------------------------------------------- Mean Squared Error: 0.24183784806212508 Mean Absolute Error: 0.39224677875386327 R2 score: 0.34118604610643233
Após variar algumas parâmetros, os valores que melhor contribuiram para as melhores performance do modelo serão usados para tunnar os hiperparâmetros
.
# número de árvores para random forest
n_estimators = [int(x) for x in np.linspace(start = 200, stop = 2000, num = 10)]
# número de variáveis para considerar em cada divisão
max_features = ['auto', 'sqrt']
# número máximo de níveis na árvore
max_depth = [int(x) for x in np.linspace(10, 110, num = 11)]
max_depth.append(None)
# número mínimo de amostras requeridas na divisão de um nó
min_samples_split = [2, 5, 10]
# número mínimo de amostras requeridas em cada nó da folha
min_samples_leaf = [1, 2, 4]
# métodos de seleção da amostra para treino em cada árvore
bootstrap = [True, False]
# criando um grid aleatório
random_grid = {'n_estimators': n_estimators,
'max_features': max_features,
'max_depth': max_depth,
'min_samples_split': min_samples_split,
'min_samples_leaf': min_samples_leaf,
'bootstrap': bootstrap,
'ccp_alpha':[0.0, 0.1, 0.2]}
# imprimindo os valores
pprint(random_grid)
{'bootstrap': [True, False], 'ccp_alpha': [0.0, 0.1, 0.2], 'max_depth': [10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, None], 'max_features': ['auto', 'sqrt'], 'min_samples_leaf': [1, 2, 4], 'min_samples_split': [2, 5, 10], 'n_estimators': [200, 400, 600, 800, 1000, 1200, 1400, 1600, 1800, 2000]}
# instanciando o algoritmo para tunning
rf = RandomForestRegressor()
# Random search dos parâmetros, usando 3 fold cross validation,
# busca em 100 diferentes combinações, e uso de todas as variáveis
rf_random = RandomizedSearchCV(estimator = rf, param_distributions = random_grid, n_iter = 100, cv = 3, verbose=2, random_state=seed, n_jobs = -1)
# treinando o modelo com RandomSearch
rf_random.fit(X_train_enc, y_train_log)
Fitting 3 folds for each of 100 candidates, totalling 300 fits
[Parallel(n_jobs=-1)]: Using backend LokyBackend with 8 concurrent workers. [Parallel(n_jobs=-1)]: Done 25 tasks | elapsed: 3.5min [Parallel(n_jobs=-1)]: Done 146 tasks | elapsed: 22.5min [Parallel(n_jobs=-1)]: Done 300 out of 300 | elapsed: 44.9min finished
RandomizedSearchCV(cv=3, estimator=RandomForestRegressor(), n_iter=100, n_jobs=-1, param_distributions={'bootstrap': [True, False], 'ccp_alpha': [0.0, 0.1, 0.2], 'max_depth': [10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, None], 'max_features': ['auto', 'sqrt'], 'min_samples_leaf': [1, 2, 4], 'min_samples_split': [2, 5, 10], 'n_estimators': [200, 400, 600, 800, 1000, 1200, 1400, 1600, 1800, 2000]}, random_state=1, verbose=2)
# verificando os melhores hiperparâmetros encontrados
rf_random.best_params_
{'n_estimators': 1800, 'min_samples_split': 5, 'min_samples_leaf': 1, 'max_features': 'sqrt', 'max_depth': 40, 'ccp_alpha': 0.0, 'bootstrap': True}
# instanciando com os melhores hiperparâmetros
best_random = rf_random.best_estimator_
# treinando com os melhores hiperparâmetros
best_random.fit(X_train_enc, y_train_log)
RandomForestRegressor(max_depth=40, max_features='sqrt', min_samples_split=5, n_estimators=1800)
# realizando as previsões
y_pred_train = best_random.predict(X_train_enc)
y_pred_val = best_random.predict(X_val_enc)
print(f'Previsão nos dados de treino:')
print('-----------------------------------------------------')
print(f'Mean Squared Error: {mean_squared_error(y_train_log, y_pred_train)}')
print(f'Mean Absolute Error: {mean_absolute_error(y_train_log, y_pred_train)}')
print(f'R2 score: {r2_score(y_train_log, y_pred_train)}\n')
print(f'Previsão nos dados de Validação:')
print('-----------------------------------------------------')
print(f'Mean Squared Error: {mean_squared_error(y_val_log, y_pred_val)}')
print(f'Mean Absolute Error: {mean_absolute_error(y_val_log, y_pred_val)}')
print(f'R2 score: {r2_score(y_val_log, y_pred_val)}')
Previsão nos dados de treino: ----------------------------------------------------- Mean Squared Error: 0.056329524690438657 Mean Absolute Error: 0.18562398299382518 R2 score: 0.8534293280239411 Previsão nos dados de Validação: ----------------------------------------------------- Mean Squared Error: 0.22737415261098484 Mean Absolute Error: 0.3800532082570786 R2 score: 0.38058800268367676
Vamos dar uma olhada na regressão com scatterplot dos dados atuais no eixo x e os valores previstos no eixo y.
# instanciando a área de plotagem
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 3))
# plotando os gráficos
sns.regplot(x=y_train_log, y=y_pred_train, ax=ax1)
ax1.grid(axis='y')
ax1.set_xlabel('Dados atuais')
ax1.set_ylabel('Dados previstos')
ax1.set_title('Previsão nos dados de TREINO')
plt.setp(ax1.get_xticklabels(), rotation=45);
sns.regplot(x=y_val_log, y=y_pred_val, ax=ax2)
ax2.grid(axis='y')
ax2.set_xlabel('Dados atuais')
ax2.set_ylabel('Dados previstos')
ax2.set_title('Previsão nos dados de VALIDAÇÃO')
plt.tight_layout()
Vimos uma certa correlação entre as variáveis.
Com os valores dos hiperparâmetros encontrados, vamos variar em torno deles e utilizar o GridSearchCV
para refinar a busca.
# {'n_estimators': 1800,
# 'min_samples_split': 5,
# 'min_samples_leaf': 1,
# 'max_features': 'sqrt',
# 'max_depth': 40,
# 'ccp_alpha': 0.0,
# 'bootstrap': True}
# criando o grid para refinar os hiperparâmetros
param_grid = {'n_estimators': [1600, 1800, 1900],
'min_samples_split': [4, 5, 6],
'min_samples_leaf': [1, 2],
'max_features': ['sqrt'],
'max_depth': [30, 40, 50],
'bootstrap': [True]}
# instanciando o algoritmo
rf = RandomForestRegressor()
# utilizando o GridSearch
grid_search = GridSearchCV(estimator = rf, param_grid = param_grid,
cv = 3, n_jobs = -1, verbose = 2)
# treinando com GridSearch
grid_search.fit(X_train_enc, y_train_log)
Fitting 3 folds for each of 54 candidates, totalling 162 fits
[Parallel(n_jobs=-1)]: Using backend LokyBackend with 8 concurrent workers. [Parallel(n_jobs=-1)]: Done 25 tasks | elapsed: 3.0min [Parallel(n_jobs=-1)]: Done 146 tasks | elapsed: 14.6min [Parallel(n_jobs=-1)]: Done 162 out of 162 | elapsed: 16.1min finished
GridSearchCV(cv=3, estimator=RandomForestRegressor(), n_jobs=-1, param_grid={'bootstrap': [True], 'max_depth': [30, 40, 50], 'max_features': ['sqrt'], 'min_samples_leaf': [1, 2], 'min_samples_split': [4, 5, 6], 'n_estimators': [1600, 1800, 1900]}, verbose=2)
# verificando os melhores hiperparâmetros encontrados
grid_search.best_params_
{'bootstrap': True, 'max_depth': 50, 'max_features': 'sqrt', 'min_samples_leaf': 1, 'min_samples_split': 4, 'n_estimators': 1600}
# instanciando com os melhores hiperparâmetros
best_random_grid = grid_search.best_estimator_
# treinando com os melhores hiperparâmetros
best_random_grid.fit(X_train_enc, y_train_log)
RandomForestRegressor(max_depth=50, max_features='sqrt', min_samples_split=4, n_estimators=1600)
# realizando as previsões
y_pred_train = best_random_grid.predict(X_train_enc)
y_pred_val = best_random_grid.predict(X_val_enc)
print(f'Previsão nos dados de treino:')
print('-----------------------------------------------------')
print(f'Mean Squared Error: {mean_squared_error(y_train_log, y_pred_train)}')
print(f'Mean Absolute Error: {mean_absolute_error(y_train_log, y_pred_train)}')
print(f'R2 score: {r2_score(y_train_log, y_pred_train)}\n')
print(f'Previsão nos dados de Validação:')
print('-----------------------------------------------------')
print(f'Mean Squared Error: {mean_squared_error(y_val_log, y_pred_val)}')
print(f'Mean Absolute Error: {mean_absolute_error(y_val_log, y_pred_val)}')
print(f'R2 score: {r2_score(y_val_log, y_pred_val)}')
Previsão nos dados de treino: ----------------------------------------------------- Mean Squared Error: 0.047176729622570475 Mean Absolute Error: 0.1697310067062503 R2 score: 0.8772451036927229 Previsão nos dados de Validação: ----------------------------------------------------- Mean Squared Error: 0.22627808757881224 Mean Absolute Error: 0.379149000795876 R2 score: 0.3835738998182916
# instanciando a área de plotagem
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 3))
# plotando os gráficos
sns.regplot(x=y_train_log, y=y_pred_train, ax=ax1)
ax1.grid(axis='y')
ax1.set_xlabel('Dados atuais')
ax1.set_ylabel('Dados previstos')
ax1.set_title('Previsão nos dados de TREINO')
plt.setp(ax1.get_xticklabels(), rotation=45);
sns.regplot(x=y_val_log, y=y_pred_val, ax=ax2)
ax2.grid(axis='y')
ax2.set_xlabel('Dados atuais')
ax2.set_ylabel('Dados previstos')
ax2.set_title('Previsão nos dados de VALIDAÇÃO')
plt.tight_layout()
Para finalizar, após encontrar os melhores hiperparâmetros vamos definir as mesmas variáveis que utilizamos no treino e treinar com todos os dados no dataset de treino.
# criando uma lista para as variáveis de entrada
feature_list = ['host_id', 'latitude', 'longitude', 'room_type', 'minimum_nights', 'number_of_reviews',
'reviews_per_month', 'calculated_host_listings_count', 'availability_365']
# dividindo os dados em X e y
X = df_train_val[feature_list]
y = df_train_val.price
# criando uma cópia para modificação
X_enc = X.copy()
# intanciando o LabelEncoder
le = LabelEncoder()
# treinando o encoder com todos os dados
le.fit(X['room_type'])
# encoding dos dados
X_enc['room_type'] = le.transform(X['room_type'])
# preenchendo o valores faltantes com 0
X_enc['reviews_per_month'] = X_enc['reviews_per_month'].fillna(0)
# instando o StanderdScaler
scaler = StandardScaler()
# treinando com todos os dados de treino
scaler.fit(X_enc)
# transformando os dados de treino
X_enc = scaler.transform(X_enc)
# normalizando a variável resposta
y_log = np.log1p(y)
# treinando o modelo com todos os dados de X e y
best_random_grid.fit(X_enc, y_log)
RandomForestRegressor(max_depth=50, max_features='sqrt', min_samples_split=4, n_estimators=1600)
Agora é o momento de certificar que o nosso treinamento está performando bem, de acordo com os dados de validação.
Vamos utilizar os dados de teste, que separamos para não ter vazamento e por fim certificar nosso modelo.
Dessa forma é o mais próximo de um modelo em produção no qual o modelo treinado realiza previsões em dados que ele nunca viu e como o modelo é generalizado, ele consegue realizar as previsões estatisticamente corretas.
# verificando as primeiras 5 linhas do conjunto de testes
df_test.head()
name | host_id | host_name | neighbourhood | latitude | longitude | room_type | price | minimum_nights | number_of_reviews | last_review | reviews_per_month | calculated_host_listings_count | availability_365 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
id | ||||||||||||||
46988142 | Apto 3qts / 6 pessoas no Bosque da Barra da Ti... | 5754974 | Carlos Eduardo | Barra da Tijuca | -22.99321 | -43.40320 | Entire home/apt | 313 | 3 | 2 | 2021-02-08 | 2.00 | 1 | 40 |
46638396 | Loft próximo ao mar em resort em São Conrado. Gym | 340964981 | João | São Conrado | -22.99498 | -43.27212 | Entire home/apt | 125 | 1 | 3 | 2021-02-14 | 1.08 | 1 | 179 |
36756540 | Ben localizado apartamento de 90mq in Copacab... | 16018428 | Renzo | Copacabana | -22.96208 | -43.17648 | Entire home/apt | 250 | 7 | 0 | NaT | NaN | 4 | 173 |
11585554 | Gávea- Excelente quarto e sala | 27229964 | Beatriz | Gávea | -22.97710 | -43.22977 | Entire home/apt | 350 | 1 | 0 | NaT | NaN | 15 | 0 |
46578541 | Aproveite o Rio na melhor localidade da cidade! | 349173829 | Caio | Ipanema | -22.98481 | -43.21362 | Entire home/apt | 220 | 2 | 0 | NaT | NaN | 1 | 364 |
Importante mencionar que agora que as transoformações devem utilizar somente o método transform
, que já foi treinado com o conjunto de treino.
Não devemos ter vazamento de dados, isso invalida o modelo.
# separando os dados em X e y no conjunto de teste
X_test = df_test[feature_list]
y_test = df_test.price
# criando uma cópia do dataset
X_test_enc = X_test.copy()
# realizando as transformações
X_test_enc['room_type'] = le.transform(X_test_enc['room_type'])
# preenchendo os dados ausentes com 0
X_test_enc['reviews_per_month'] = X_test_enc['reviews_per_month'].fillna(0)
# realizando as transformações
X_test_enc = scaler.transform(X_test_enc)
# normalizando a variável resposta
y_test_log = np.log1p(y_test)
# realizando as previsões
y_pred_train_total = best_random_grid.predict(X_enc)
y_pred_test = best_random_grid.predict(X_test_enc)
print(f'Previsão nos dados de treino total:')
print('-----------------------------------------------------')
print(f'Mean Squared Error: {mean_squared_error(y_log, y_pred_train_total)}')
print(f'Mean Absolute Error: {mean_absolute_error(y_log, y_pred_train_total)}')
print(f'R2 score: {r2_score(y_log, y_pred_train_total)}\n')
print(f'Previsão nos dados de Teste:')
print('-----------------------------------------------------')
print(f'Mean Squared Error: {mean_squared_error(y_test_log, y_pred_test)}')
print(f'Mean Absolute Error: {mean_absolute_error(y_test_log, y_pred_test)}')
print(f'R2 score: {r2_score(y_test_log, y_pred_test)}')
Previsão nos dados de treino total: ----------------------------------------------------- Mean Squared Error: 0.04627544695210093 Mean Absolute Error: 0.16862386583942493 R2 score: 0.8785110926877852 Previsão nos dados de Teste: ----------------------------------------------------- Mean Squared Error: 0.2199302824060129 Mean Absolute Error: 0.38104048502370497 R2 score: 0.41041561263625315
# definindo a área de plotagem
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 3))
# plotando os gráficos
sns.regplot(x=y_log, y=y_pred_train_total, ax=ax1)
ax1.grid(axis='y')
ax1.set_xlabel('Dados atuais')
ax1.set_ylabel('Dados previstos')
ax1.set_title('Previsão nos dados de TREINO')
plt.setp(ax1.get_xticklabels(), rotation=45);
sns.regplot(x=y_test_log, y=y_pred_test, ax=ax2)
ax2.grid(axis='y')
ax2.set_xlabel('Dados atuais')
ax2.set_ylabel('Dados previstos')
ax2.set_title('Previsão nos dados de TESTE')
plt.tight_layout()
# desnormalizando os dados previstos
np.expm1(y_pred_test)
array([258.958392 , 276.19344631, 237.17828711, ..., 226.92581208, 373.45346721, 330.07111458])
# inserindo no conjuntod de dados de treino
df_test['predict'] = np.expm1(y_pred_test)
# verificando as primeiras 5 linhas da variável alvo e o valor previsto
df_test[['price', 'predict']].head()
price | predict | |
---|---|---|
id | ||
46988142 | 313 | 258.958392 |
46638396 | 125 | 276.193446 |
36756540 | 250 | 237.178287 |
11585554 | 350 | 301.844550 |
46578541 | 220 | 373.714178 |
Comparando os resultados finais com a baseline:
Baseline:
Modelo Final: