Primeira vez aqui? Seja bem vindo e cheque o FAQ!
x

Um exercício de Machine Learning usando a base de dados Restaurant Revenue Prediction" do Kaggle

0 votos
7 visitas

1 Resposta

0 votos
respondida Nov 5 por Pedro Watuhã (1 ponto)  

Para melhor visualizar alguns resultados, segue o link para o Github com a solução do exercício: https://github.com/pedrowatuha/restaurant_revenue

Nesse trabalho, propõe-se explorar as diferenças de Revenue em restaurantes da Turquia ao utilizar modelos estatísticos para prever possíveis revenues de outros restaurantes a partir das características e estimativas desses. Percebe-se que o train set do problema tem seu revenue bem definido junto às características e, portanto, modelos supervisionados serão preferíveis.
O banco de dados fornecerá o ID do restaurante de acordo com o próprio banco de dados, a data de abertura do restaurante, a cidade da Turquia em que o restaurante está localizado, se a cidade é considerada grande ou não, o tipo de alimentação e de restaurante e variáveis não denominadas relacionadas a população local, desempenho econômico local, condições geográficas e relacionados. Dessa forma, inicia-se sua exploração:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import statsmodels.api as sm
from sklearn.linear_model import LinearRegression
from sklearn.linear_model import Lasso, Ridge, ElasticNet
from sklearn.model_selection import GridSearchCV

train = pd.read_csv("train.csv")
test = pd.read_csv("test.csv")

Primeiramente, quanto à variável de data de abertura, aparenta ser melhor para se quantificar o tempo de abertura do restaurante em vez da data, portanto a transformemos de data em uma variável discreta inteira:

dic = {}
n=0
for k in train["Open Date"]:
    train["Open Date"][n] = float(2014 - int(k[-4:]))
    n+=1
n=0
for k in test["Open Date"]:
    test["Open Date"][n] = float(2014 - int(k[-4:]))
    n+=1
train.rename(columns = {"Open Date": "age"}, inplace=True)
test.rename(columns = {"Open Date": "age"}, inplace=True)

Em segundo lugar, para estimações futuras, é mais interessante que as variáveis categóricas apresentem-se em formato de Dummies. Por conseguinte, no primeiro caso, cria-se uma Dummie para cidades grandes, pois caso seja 0 será outro e, no segundo caso, criam-se dummies para Food Court, Inline e Drive-Thru, pois caso não seja algum desses, será mobile.

encoded_columns = pd.get_dummies(train["City Group"])
train=train.join(encoded_columns["Big Cities"])

encoded_columns = pd.get_dummies(test["City Group"])
test=test.join(encoded_columns["Big Cities"])

encoded_columns = pd.get_dummies(train["Type"])
train=train.join(encoded_columns)

encoded_columns = pd.get_dummies(test["Type"])
test=test.join(encoded_columns).drop(columns=["MB"])

Em seguida, inicia-se a análise descritiva dessas variáveis. Primeiramente, observemos como operam as distribuições de Revenue, do tipo de cidade e do tipo de restaurante.

x = train["revenue"]
sns.distplot(x)
plt.title("Distribution of Revenue")

A imagem será apresentada aqui.

y=train["Big Cities"]
sns.distplot(y, kde=False)
plt.title("Big Cities")

A imagem será apresentada aqui.

train["Type"].value_counts().plot(kind="bar")
plt.title("Types of Restaurant")

A imagem será apresentada aqui.

Em seguida, analisemos a correlação visual entre a variável idade, que denomina o tempo de existência do estabelecimento e a sua revenue. Nessa imagem, aparenta ser perceptível a correlação entre ambas, indicando-nos que estabelecimentos mais antigos, por terem receitas maiores, mantiveram-se por períodos maiores de tempo ou que, conforme sua idade aumenta, ele encontra formas de expandir sua receita pela clientela assídua ou formas semelhantes.

x=train["age"]
y=train["revenue"]
plt.plot(x,y,"go")
plt.title("Age versus Revenue")
plt.xlabel("Age")
plt.ylabel("Revenue")

A imagem será apresentada aqui.

Em seguida, plotam-se os gráficos para a correlação entre as outras 37 variáveis, P1-P37, e a receita. As imagens dessa parte estarão disponíveis no link do Github.

x = train.drop(columns=["Id","age","City","City Group","Type","Big Cities","DT","FC","IL","revenue"])
y =train["revenue"]
fig, axs = plt.subplots(37, figsize=(15,100),sharey=True)
n=0
for col in x.columns:
    axs[n].plot(x[col],y,"go")
    axs[n].set_title(str(col)+" vs Revenue")
    n+=1

Por fim, analisa-se a matriz de correlação entre essas variáveis apresentada como um Heatmap para tornar a análise visualmente melhor, visto que a matriz contém mais de 1000 termos. Mesmo assim, as conclusões obtidas são claras de que, individualmente, todas as variáveis aparentam ser pouco correlacionadas com a receita.

plt.figure(figsize=(50,50))
sns.heatmap(train.corr())
sns.set(font_scale=10)

A imagem será apresentada aqui.

A partir desses dados, volta-se ao desenvolvimento de um modelo para realizar previsões. Inicialmente, propõe-se a utilização de um modelo linear para realizar a estimativa. Todavia, espera-se que essa estimativa original dificilmente seja adequada, visto que o train set apresenta apenas 137 observações e mais de 40 variáveis explicativas.

y = train["revenue"]
x = train.drop(columns=["Id","City","City Group","Type","revenue"])
x = sm.add_constant(x)
m = sm.OLS(y,x.astype(float))
est = m.fit()
print(est.summary())

A imagem será apresentada aqui.

Assim como esperado, as variáveis não se provaram tão significativas e o score \( R^2 \) ainda menos. Apenas as variáveis FC, P26, P20, P8 e Age se provaram significativas a um nível de 10% e apenas P8 e Age a um nível de 5%. Além disso, o \(R^2\) obtido de 0,354, já diminuto, prova-se ainda menor quando o consideramos de forma ajustada, apenas de 0,076, análise complementar válida dada a quantidade de variáveis utilizadas no processo.

Em seguida, propõe-se a utilização de outros modelos para otimizar a análise. Para isso, utilizam-se modelos regularizadores para manter o modelo linear, mas tentar otimizar os resultados antes obtidos. Para isso, serão utilizados o modelo LASSO, o modelo Ridge e o modelo Elastic-Net. Para cada caso, serão testados uma série de parâmetros em cada modelo e aquele que obtiver a melhor estimativa será usado para previsão.
Para o modelo LASSO:

y = train["revenue"]
x = train.drop(columns=["Id","City","City Group","Type","revenue"])
par = {
    'alpha' : [.01, .1, .25, .5, .75, 1, 5, 10],
    'fit_intercept' : [True, False],
    'normalize' : [True,False],
    'tol' : [0.001, 0.005, 0.01, 0.05, 0.1],
}

las=Lasso()
grid = GridSearchCV(las, par, scoring='r2', n_jobs=-1)
grid.fit(x,y)
print(grid.best_params_)
print(grid.best_score_)

Resultado: {'alpha': 10, 'fit_intercept': False, 'normalize': True, 'tol': 0.1}
-0.4260694167871029

Para o modelo Ridge:

y = train["revenue"]
x = train.drop(columns=["Id","City","City Group","Type","revenue"])
par = {
    'alpha' : [.01, .1, .25, .5, .75, 1, 5, 10],
    'fit_intercept' : [True, False],
    'normalize' : [True,False],
    'tol' : [0.001, 0.005, 0.01, 0.05, 0.1],
}

rid=Ridge()
grid = GridSearchCV(rid, par, scoring='r2', n_jobs=-1)
grid.fit(x,y)
print(grid.best_params_)
print(grid.best_score_)

Resultado: {'alpha': 5, 'fit_intercept': True, 'normalize': True, 'tol': 0.001}
0.023808300504311774

Modelo Elastic Net:

y = train["revenue"]
x = train.drop(columns=["Id","City","City Group","Type","revenue"])
par = {
    'alpha' : [.01, .1, .25, .5, .75, 1, 5, 10],
    'fit_intercept' : [True, False],
    'normalize' : [True,False],
    'tol' : [0.001, 0.005, 0.01, 0.05, 0.1],
}

ela=ElasticNet()
grid = GridSearchCV(ela, par, scoring='r2', n_jobs=-1)
grid.fit(x,y)
print(grid.best_params_)
print(grid.best_score_)

Resultado: {'alpha': 0.1, 'fit_intercept': True, 'normalize': True, 'tol': 0.05}
0.02230544354633106

A partir dos resultados obtidos, percebe-se que o modelo LASSO apresenta a pior performance, enquanto os modelos de Elastic Nets e Ridge apresentam desempenhos bem semelhantes. Portanto, utilizaremos o modelo Ridge para realizar a estimativa do nosso test set.

y = train["revenue"]
x = train.drop(columns=["Id","City","City Group","Type","revenue"])
X = test.drop(columns=["Id","City","City Group","Type"])
rid=Ridge(alpha=5,fit_intercept=True, normalize=True, tol =0.001)
rid.fit(x,y)
yhat = rid.predict(X)
sns.distplot(yhat)

A imagem será apresentada aqui.

Portanto, ainda que não se analisem os dados individualmente, visto que são 100000 amostras, mas podemos observar que a distribuição se assemelha, ainda que em nível menor, à distribuição do train set, levemente deslocado para a direita.

...