# This Python 3 environment comes with many helpful analytics libraries installed
# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python
# For example, here's several helpful packages to load

import numpy as np # linear algebra
import pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)

# Input data files are available in the read-only "../input/" directory
# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory

import os
for dirname, _, filenames in os.walk('/kaggle/input'):
    for filename in filenames:
        print(os.path.join(dirname, filename))

# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using "Save & Run All" 
# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session
import seaborn as sns
import matplotlib.pyplot as plt

pd.set_option('display.max_columns', None)

df = pd.read_csv("../input/house-prices-advanced-regression-techniques/train.csv", index_col=0)
# Selecionei um subconjunto das variáveis de entrada para fins de simplificação
FEATURES_ANALISAR = ['MSSubClass', 'MSZoning', 'LotFrontage', 'LotArea',  'Street', 'Alley', 'Neighborhood', 'HouseStyle', 'OverallQual', 'OverallCond', 'YearBuilt', 'CentralAir', 'BsmtCond', 'FullBath', 'HalfBath', 'BedroomAbvGr', 'KitchenQual', 'Fireplaces', 'SalePrice']
df = df.loc[:, FEATURES_ANALISAR]
df
"""
Olhando na tabela (e em alguma descrição do dataset, se disponível), decidimos o que é categórico e numérico
"""
NominalCategorical = ['MSSubClass', 'MSZoning', 'Street', 'Alley', 'Neighborhood', 'HouseStyle', 'CentralAir', 'BsmtCond', 'KitchenQual']
OrdinalCategorical = ['OverallQual', 'OverallCond', 'YearBuilt']
Numeric = ['LotFrontage', 'LotArea', 'FullBath', 'HalfBath', 'BedroomAbvGr', 'Fireplaces', 'SalePrice']

"""
Tamanho do dataset:
"""
print("{} linhas\n{} colunas/features.".format(df.shape[0], df.shape[1]))
"""
# Medição, deleção e imputação de dados ausentes
"""
# Funcao do Pandas usada para contar o numero de valores vazios de cada coluna
data = df.isna().sum(axis=0)
y = list(range(df.shape[1]))
x = data.values

# Criamos uma figura
fig, ax = plt.subplots(figsize=(8, 10))

# Plota as barras
ax.barh(y=y, width=x)

# Adiciona informações no gráfico
ax.set_yticks(y)
ax.set_yticklabels(df.columns.values)
ax.set_title("Quantidade de variáveis ausentes por coluna")
plt.show()
"""
Temos 3 features que apresentam valores ausentes. Vamos analisar uma por uma começando por 
### Alley
"""
df['Alley'].value_counts()
"""
Como a feature Alley tem a grande maioria dos dados ausentes, é do tipo categórica e suas categorias estão divididas em números muito similares (50 e 41), decidimos por excluir esta coluna da análise:
"""
FEATURES_ANALISAR.remove('Alley')
df = df.loc[:, FEATURES_ANALISAR]
df_original = df.loc[:, FEATURES_ANALISAR]
df
"""
### LotFrontage

Como LotFrontage pode ser considerado como uma feature numérica, podemos imputar os dados ausentes usando a técnica de Imputação por Regressão Linear.

Por motivos de simplicidade, será modelado uma regressão para predizer os dados ausentes de LotFrontage levando em consideração apenas LotArea e SalePrice, ambas variáveis numéricas.
"""
# Criamos um dataframe com os dados de LotFrontage, Lot Area e SalePrice
df_imput_regress = pd.concat([df['LotFrontage'], df['LotArea'], df['SalePrice']], axis=1)
df_imput_regress.head()
from sklearn.experimental import enable_iterative_imputer
from sklearn.impute import IterativeImputer

# Criamos um objeto que fará a Imputação por Regressão
imp_mean = IterativeImputer(random_state=0)
# Treinamos a regressão com os dados disponiveis
imp_mean.fit(df_imput_regress.values)

# Agora, faremos uma regressão nos mesmos dados usados no treinamento, para
# gerar valores numéricos para substituir os valores ausentes de LotFrontage
X = df_imput_regress.values
regr_output = imp_mean.transform(X)
regr_output
# Agora substituimos a primeira coluna de X (output do regressor) no nosso dataframe df
df['LotFrontage'] = regr_output[:, 0]
"""
Agora, como podemos perceber, LotFrontage não tem mais dados nulos
"""
df['LotFrontage'].isna().sum()
"""
### BsmtCond

É uma variávei categórica ordinal. Portanto, não faria sentido substituir por um número decimal, como por exemplo uma média ou uma regressão.

Então, iremos substituir os dados ausentes pelos dados que aparecem com maior frequência nesta feature.
"""
df['BsmtCond'].value_counts()
"""
Podemos perceber que 'TA' é a categoria com maior presença. Iremos substituí-la nos dados ausentes:
"""
#.fillna substitui o argumento nos dados ausentes
df['BsmtCond'] = df['BsmtCond'].fillna('TA')
"""
#### Todos os dados ausentes foram deletados ou substituídos:
"""
df.isna().sum(axis=0)
"""
# Outliers
"""
"""
Para detectar outliers, vamos utilizar 2 técnicas:
 - Análise visual (através de boxplot e histogramas)
 - Z-Test, SE tiver alguma variável float com distribuição normal ou normal com leve assimetria
 
Além disto, neste momento vamos apenas verificar outliers de variáveis codificadas de forma numérica
"""
selected_columns = Numeric + OrdinalCategorical
df[selected_columns].head()

"""
### Detecção visual
"""
fig, axes = plt.subplots(nrows=1, ncols=10, figsize=(15, 5))

for i,col in enumerate(selected_columns):
    axes[i].boxplot(df[col])
    axes[i].set_title(col)

plt.tight_layout()
fig, axes = plt.subplots(nrows=5, ncols=2, figsize=(15, 15))
# Quando criamos graficos com multiplas dimensoes, axes vira um array 2D. Então
# vamos transformar ele numa lista para iterar durante a criação do grafico
axes = axes.flatten()

# Iterando de grafico em grafico
for i,ax in enumerate(axes):
    ax.hist(df[selected_columns[i]])
    ax.set_title(selected_columns[i])

plt.tight_layout()
"""
Vamos fazer um gráfico de dispersão 2D das variáveis LotArea e LotFrontage para verificar a relação entre elas
"""
fig, ax = plt.subplots()

ax.scatter(x=df['LotArea'], y=df['LotFrontage'])
plt.show()
"""
Analisando os histogramas, diagrama de caixas e gráfico de dispersão, decidimos filtrar duas features:
 - Valores de LotArea maiores que 100000 serão excluídos
 - Valores de LotFrontage maiores que 200 serão excluídos
"""
print("Tamanho do dataset antes dos filtros: {}".format(df.shape))

mask = df['LotFrontage'] < 200
df = df[mask]
mask = df['LotArea'] < 100000
df = df[mask]

print("Tamanho do dataset depois dos filtros: {}".format(df.shape))
"""
### Detecção usando Z-Test
"""
"""
Para a variável SalePrice, vamos usar o método Z-Test para remover outliers:
"""
from scipy import stats

# df["SalePrice"]
fig, ax = plt.subplots(nrows=1, ncols=2, figsize=(15, 5))

data = df["SalePrice"]
z_data = np.abs(stats.zscore(df["SalePrice"]))
ax[0].hist(data)
ax[0].set_xlabel("Valores reais de SalePrice")
ax[1].hist(z_data)
ax[1].set_xlabel("Valores Z de SalePrice")
ax[1].vlines(x=3, ymin=0, ymax=850, colors='red')
plt.show()
"""
Vamos remover todos os dados com Z >= 3
"""
print("Tamanho do dataset antes dos filtros: {}".format(df.shape))

mask = np.abs(stats.zscore(df["SalePrice"])) < 3
df = df[mask]

print("Tamanho do dataset depois dos filtros: {}".format(df.shape))
"""
# Feature Engineering
"""
"""
Vamos criar uma nova feature de forma bem simples, dividindo a Área do terreno pelo tamanho da frente do terreno, ou seja, LotArea/LotFrontage
"""
df['RatioAreaFrontage'] = df['LotArea'] / df['LotFrontage']

df[['RatioAreaFrontage', 'LotArea', 'LotFrontage']]
"""
# Feature Selection
"""
"""
Vamos continuar apenas com as variáveis numéricas e ordinais categórias codificadas em forma de números, por simplicidade.

Vamos descartar 1 feature usando o teste f-regression
"""
selected_columns = ['LotFrontage', 'LotArea', 'FullBath', 'HalfBath', 'BedroomAbvGr', 'Fireplaces', 'OverallQual', 'OverallCond', 'YearBuilt', 'RatioAreaFrontage']
x = df[selected_columns]
y = df['SalePrice']
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import chi2
from sklearn.feature_selection import f_regression

# k é o numero de features que NÃO serão jogadas foras. Vamos primeiro ver os resultados, depois eliminar alguma feature.
k = x.shape[1]
# Utilizamos um método do sklearn para isso, usando a estratégia Chi Squared.
selector = SelectKBest(f_regression, k=k)
x_new = selector.fit_transform(x, y)
"""
#### Visualizando os resultados do f-regression
"""
# Utilizo o log10 pois os valores são ou muito grandes, ou muito pequenos
scores = -np.log10(selector.pvalues_)

x_plot = list(range(len(scores)))

fig, ax = plt.subplots(figsize=(8, 4))
plt.bar(x_plot, scores)
ax.set_title("Score do método f-regression para Feature Selection")
ax.set_xticks(x_plot)
ax.set_xticklabels(selected_columns, rotation=45)
plt.show()
"""
Podemos perceber que a feature "OverallCond" apresenta os menores resultados, e portanto, vamos eliminá-la do nosso dataset.
"""
print("Tamanho do dataset antes dos filtros: {}".format(df.shape))

df = df.drop(['OverallCond'], axis=1)

print("Tamanho do dataset depois dos filtros: {}".format(df.shape))
"""
# Feature Encoding
"""
"""
Olhando para a tabela do dataset, podemos perceber que a feature "CentralAir" tem apenas 2 valores, correspondentes a verdadeiro e falso: 'Y' e 'N':
"""
df['CentralAir'].value_counts()
"""
Portanto, levando em consideração que é possível que a presença de ar condicionado central possa valorizar a casa, podemos codificar 'Y'=1 e 'N'=0:
"""
df['CentralAir'].replace(to_replace='Y', value=1, inplace=True)
df['CentralAir'].replace(to_replace='N', value=0, inplace=True)

df['CentralAir'].value_counts()
"""
# Data Scaling
"""
"""
Vamos novamente apenas tratar de variáveis codificadas como números
"""
selected_columns = ['LotFrontage', 'LotArea', 'FullBath', 'HalfBath', 'BedroomAbvGr', 'Fireplaces', 'OverallQual', 'YearBuilt', 'RatioAreaFrontage', 'SalePrice']
df[selected_columns].describe()
"""
Podemos perceber na tabela acima que os existem valores mínimos que começam em 21 (Lot Frontage), 1300 (Lot Area) e 26.9 (RatioAreaFrontage). Além disso, os valores máximos de muitas tabelas são valores altos, como 182 (LotFrontage), 70761 (LotArea), entre outros.

Isso pode resultar em problemas para o treinamento de uma rede neural, então, vamos normalizar esses dados usando o estalonador MinMax do sklearn:
"""
from sklearn.preprocessing import MinMaxScaler
scaler = MinMaxScaler()
data = df[selected_columns]
scaler.fit(data)
"""
O escalonador MinMax está ajustado para os dados presentes em selected_columns.
Agora iremos reescalonar estes dados e verificar se eles estão dentro de um intervalo [0,1]:
"""
# Reescalonamos os dados
data_scaled = scaler.transform(data)

# Criamos um dataframe para facilitar a visualização
data_scaled = pd.DataFrame(data_scaled)
# "Devolvemos" os nomes das features e os índices para o dataframe
data_scaled.columns = selected_columns
data_scaled.index = df.index

data_scaled.describe()
"""
Como podemos ver, todos os valores mínimos estão em 0 e todos os valores máximos estão em 1. Os dados foram reescalonados com sucesso.

Agora precisamos incorporar estes dados no nosso dataframe df:
"""
df = df.drop(selected_columns, axis=1)
df = pd.concat([df, data_scaled], axis=1)
"""
## Dataset "Inicial"
"""
df_original
"""
## Dataset "Final"
"""
df
import pandas as pd

print("Trabalho 1 de IA")
df = pd.read_csv("../input/aula-2-ia-dataset/CasasParaAlugar.csv")

df
df.head()
df['city'].value_counts().head(10).plot.bar()
df['city'].value_counts().sort_index().plot.bar()
df['area'].value_counts().head(10).plot.bar()
df['bathroom'].value_counts().head(10).plot.bar()
df['animal'].value_counts().head(10).plot.bar()
df['hoa (R$)'].value_counts().sort_index().plot.area()
df.plot.scatter(x='area', y='hoa (R$)')
df.isnull().count()
import seaborn as sns
sns.countplot(df['city'].head(20))
ax = sns.distplot(df['area'], bins = 20, kde = False)
sns.boxplot(x='city',
           y ='area',
           hue = 'bathroom',
           data = df)
r = df.corr()
sns.heatmap(r)
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline

data_train = pd.read_csv('../input/aula-2-ia-dataset/CasasParaAlugar.csv')
#data_test = pd.read_csv('.../input/aula-2-ia-dataset/CasasParaAlugar.csv')

data_train.sample(3)
sns.barplot(x="city", y="area", hue="bathroom", data=data_train);
sns.pointplot(x="city", y="area", hue="animal", data=data_train,
              palette={"acept": "blue", "not acept": "pink"},
              markers=["*", "o"], linestyles=["-", "--"]);
"""
#### Existem muito mais análises que podem ser feitas, e neste dataset existem MUUITAS outras variáveis que precisariam ser tratadas para o dataset ficar adequado para o treinamento de uma rede neural.

#### Ainda assim, estes são exemplos de alguns dos passos envolvidos na análise e pré processamento de dados antes da etapa de modelagem.
"""