import pandas as pd
import io
import requests
url="https://media.githubusercontent.com/media/fbarth/ml-espm/master/data/20140917_imoveis_filtrados_final.csv_shaped.csv"
s=requests.get(url).content
df = pd.read_csv(io.StringIO(s.decode('utf-8')), sep=",")

df.head()

%matplotlib inline
import seaborn as sns
import matplotlib.pyplot as plt
plt.subplots(figsize=(10, 8))
cmap = sns.cubehelix_palette(rot=-.2, as_cmap=True)
ax = sns.scatterplot(x="area", y="preco",
                     hue="suites", size="vagas",
                     palette=cmap, sizes=(10, 200),
                     data=df)

df['bairro'].value_counts()

"""
Explanation: Calculando o preço de apartamentos na cidade de São Paulo
O objetivo deste projeto é construir um modelo preditivo capaz de calcular o preço de um imóvel no bairro Vila Nova Conceição na cidade de São Paulo. 
Para completar este projeto cada aluno deverá seguir as orientações que estão neste notebook e preencher as células vazias. 
Aquisição, pré-processamento e análise descritiva
End of explanation
"""


# @hidden_cell
df = df[df['bairro'] == 'vila-nova-conceicao']

"""
Explanation: Considere apenas os imóveis do bairo vila-nova-conceicao
End of explanation
"""


df.shape

%matplotlib inline
import seaborn as sns
import matplotlib.pyplot as plt
plt.subplots(figsize=(10, 8))
cmap = sns.cubehelix_palette(rot=-.2, as_cmap=True)
ax = sns.scatterplot(x="area", y="preco",
                     hue="suites", size="vagas",
                     palette=cmap, sizes=(10, 200),
                     data=df)

df.head()

"""
Explanation: Depois de considerar apenas os imóveis do bairro vila-nova-conceicao o tamanho do dataset precisa ser exatamente igual a:
End of explanation
"""


# @hidden_cell
df = df[df['suites'] <= df['dormitorios']]
df = df[df['suites'] <= df['banheiros']]

"""
Explanation: A quantidade suites não pode ser maior que a quantidade de dormitórios e a quantidade de suites também não pode ser maior que a quantidade de banheiros. Exclua todos os exemplos que não satisfazem esta restrição. Estes exemplos provavelmente são erros de coleta de dados.
End of explanation
"""


df.shape

%matplotlib inline
import seaborn as sns
import matplotlib.pyplot as plt
plt.subplots(figsize=(10, 8))
cmap = sns.cubehelix_palette(rot=-.2, as_cmap=True)
ax = sns.scatterplot(x="area", y="preco",
                     hue="suites", size="vagas",
                     palette=cmap, sizes=(10, 200),
                     data=df)

"""
Explanation: Depois deste filtro o dataset precisa ter o tamanho abaixo:
End of explanation
"""


# @hidden_cell
df = df.drop(columns=['bairro'])

"""
Explanation: Visto que agora a variável bairro tem apenas um valor, você deve remover a mesma
End of explanation
"""


df.head()

"""
Explanation: Depois deste filtro o dataset precisa ter a seguinte estrutura:
End of explanation
"""


# @hidden_cell
x = df['preco'].describe()
x

"""
Explanation: Qual é o valor mínimo e máximo dos preços dos imóveis?
End of explanation
"""


df.head()

from sklearn.model_selection import train_test_split
x_train, x_test, y_train, y_test = train_test_split(df.iloc[:,1:12], df['preco'], test_size=0.2, random_state=4)

x_train.head()

"""
Explanation: Divisão dos datasets
End of explanation
"""


print(x_train.shape)
print(y_train.shape)
print(x_test.shape)

from sklearn.linear_model import LinearRegression
model = LinearRegression().fit(x_train, y_train)

"""
Explanation: Criação e avaliação do modelo preditivo
Crie um modelo de regressão utilizando os algoritmos e transformações nos atributos que você considera mais adequados.
Valide o modelo desenvolvido considerando os datasets X_test e y_test. Espera-se que o erro médio absoluto seja inferior a duzentos mil reais (R$ 200.000,00). 
Descreva nas células abaixo todas as etapas necessárias para o desenvolvimento e validação do modelo.
Regressão Linear sem engenharia de atributos
End of explanation
"""


predicted = model.predict(x_test)

from sklearn.metrics import mean_squared_error, r2_score, mean_absolute_error
rmse = mean_squared_error(y_test, predicted)
r2 = r2_score(y_test, predicted)
mae = mean_absolute_error(y_test, predicted)
print('rmse = %', rmse)
print('r2 = %', r2)
print('mae = %', mae)

"""
Explanation: Validação do modelo
End of explanation
"""


from sklearn.ensemble import RandomForestRegressor
results = pd.DataFrame(columns=['estimators','r2'])
for i in range(100, 2000, 100):
    clf = RandomForestRegressor(n_estimators=i, max_depth=None, random_state=4, oob_score=True)
    clf.fit(x_train, y_train)
    results = results.append({'estimators':i, 'r2': clf.oob_score_}, ignore_index=True)

results.plot(x='estimators', y='r2')

clf = RandomForestRegressor(n_estimators=400, max_depth=None, random_state=4, oob_score=True)
clf.fit(x_train, y_train)

print(clf.oob_score_)
print(clf.feature_importances_)
print(x_train.columns)

"""
Explanation: Random Forest sem modificação adicional de atributos e modificando apenas a quantidade de árvores
End of explanation
"""


predicted = clf.predict(x_test)

from sklearn.metrics import mean_squared_error, r2_score, mean_absolute_error
rmse = mean_squared_error(y_test, predicted)
r2 = r2_score(y_test, predicted)
mae = mean_absolute_error(y_test, predicted)
print('rmse = %', rmse)
print('r2 = %', r2)
print('mae = %', mae)

"""
Explanation: Validação do modelo
End of explanation
"""


#Generate a new feature matrix consisting of all polynomial combinations 
#of the features with degree less than or equal to the specified degree. 
#For example, if an input sample is two dimensional and of the form [a, b], 
#the degree-2 polynomial features are [1, a, b, a^2, ab, b^2].

from sklearn.preprocessing import PolynomialFeatures
transformer = PolynomialFeatures(degree=2, include_bias=False)
transformer.fit(x_train)
train_ = transformer.transform(x_train)

print(x_train.shape)
print(train_.shape)

from sklearn.linear_model import LinearRegression
model = LinearRegression().fit(train_, y_train)

"""
Explanation: Regressão Linear com transformação polinomial
End of explanation
"""


transformer.fit(x_test)
test_ = transformer.transform(x_test)
predicted = model.predict(test_)

from sklearn.metrics import mean_squared_error, r2_score, mean_absolute_error
rmse = mean_squared_error(y_test, predicted)
r2 = r2_score(y_test, predicted)
mae = mean_absolute_error(y_test, predicted)
print('rmse = %', rmse)
print('r2 = %', r2)
print('mae = %', mae)

"""
Explanation: Validação do modelo
End of explanation
"""


from sklearn.model_selection import GridSearchCV
param_grid = { 
    'n_estimators': [100, 200, 300, 400, 500, 600, 700, 800, 900, 1000],
    'max_features': ['sqrt', 'log2', 3, 4, 5, 6],
    'max_depth' : [2, 10, 20, 100, None]
}
rfc=RandomForestRegressor(random_state=4)
CV_rfc = GridSearchCV(estimator=rfc, param_grid=param_grid, cv= 3, verbose=1, n_jobs=-1)
CV_rfc.fit(train_, y_train)
CV_rfc.best_params_

clf3 = RandomForestRegressor(n_estimators=100, max_features = 6, max_depth=20, random_state=4, oob_score=True)
clf3.fit(train_, y_train)

print(clf3.oob_score_)

"""
Explanation: Random Forest com transformacao polinomial
End of explanation
"""


predicted = clf3.predict(test_)
from sklearn.metrics import mean_squared_error, r2_score, mean_absolute_error
rmse = mean_squared_error(y_test, predicted)
r2 = r2_score(y_test, predicted)
mae = mean_absolute_error(y_test, predicted)
print('rmse = %', rmse)
print('r2 = %', r2)
print('mae = %', mae)

"""
Explanation: Validação do modelo
End of explanation
"""


def diff(x, y):
    return (x-y)
    
resultados = pd.DataFrame({'real': y_test,'rf_grid_polinomial': predicted})
resultados['rf_grid_polinomial_dif'] = resultados.apply(lambda x: diff(x['real'], x['rf_grid_polinomial']), axis=1)
resultados = resultados.join(x_test)
resultados.head()

ax = resultados.plot(x='area', y='rf_grid_polinomial_dif', kind='scatter')
ax.set_title('Análise dos erros')

"""
Explanation: Análise dos resultados
End of explanation
"""


