# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .py
#       format_name: light
#       format_version: '1.5'
#       jupytext_version: 1.14.4
#   kernelspec:
#     display_name: Python 3
#     language: python
#     name: python3
# ---

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from pandas.plotting import scatter_matrix


def missing_values_table(df): 
    mis_val = df.isnull().sum()
    mis_val_percent = 100 * df.isnull().sum()/len(df)
    mis_val_table = pd.concat([mis_val, mis_val_percent], axis=1)
    mis_val_table_ren_columns = mis_val_table.rename(
    columns = {0 : 'Valores ausentes', 1 : '% do valor total'})
    return mis_val_table_ren_columns.loc[(mis_val_table_ren_columns!=0).any(axis=1)]


#load data
df = pd.read_csv("data/train.csv")

# ## Scatter plot geral - validar se os dados se apresentam de forma esparça

df

# +
#scatter_matrix(df, figsize=(20, 20), diagonal='kde')
# -

# ## Avaliar quantidade de Missing Values

miss = missing_values_table(df)

miss = miss.sort_values(by=["Valores ausentes"], ascending=False)

miss

plt.plot(sorted(miss['% do valor total'].values))
plt.grid(True)
plt.ylabel("% Valores ausentes")
plt.show()
miss['Valores ausentes'].hist(bins=15, grid=False)
plt.ylabel("Valores ausentes")
plt.xticks([])
plt.show()



df[miss.index].dtypes

# De acordo com alguns estudos, estimar os Missing values em um conjunto de dados onde o valor ultrapassa 40%, existe uma grande chance de prejudicar o aprendizado.
# Desse modo, os atributos abaixo cerca de 5, estão a partir de 47% até 99%. Sendo assim podemos partir por dois caminhos. Eliminar do conjunto de dados, ou estudar cada atributo e tentar substituir os valores ausentes por um valor que represente essa ausência.
#
# Atributo  | Valores ausentes | % do valor total | Descrição
# --- | --- | --- | ---
# PoolQC  |	1453 |	`99.520` | Pool quality
# MiscFeature  |	1406 |	`96.301` | Miscellaneous feature not covered in other categories
# Alley  |	1369 |	`93.767` | Type of alley access
# Fence  |	1179 |	80.753 | Fence quality
# FireplaceQu  |	690 |	47.260 | Fireplace quality
#
# Sendo assim, vou estudar os 5 atributos com o objetivo de substituir os valores ausentes.

for c in df[['PoolQC', 'MiscFeature', 'Alley', 'Fence', 'FireplaceQu']].columns:
    print(c,df[c].unique())

# 3 atributos estão relacionados a qualidade, 1 relacionado ao tipo de acesso e outro serve como 'outros', dessa forma os atributos que são relacionados a qualidade, apesar de categóricos, estão dentro de uma escala de distância. Os demais não possuem essa escala.

df.PoolQC.fillna('NtE', inplace=True)
df.Fence.fillna('NtE', inplace=True)
df.FireplaceQu.fillna('NtE', inplace=True)
df.MiscFeature.fillna('None', inplace=True)
df.Alley.fillna('None', inplace=True)

col_n = []
col_c = []
for c in miss.index:
    #print(c,df[c].dtypes,df[c].unique())
    if df[c].dtypes == 'object':
        col_c.append(c)
    else:
        col_n.append(c)

# Para as os demais, existem outras abordagens como substituição por vizinhos mais próximos dentre outras, mas para esse experimento vou utilizar a substituição pelos valores médios ou moda

from sklearn.impute import SimpleImputer

imputerN = SimpleImputer(missing_values = np.nan, strategy = 'mean')
imputerC = SimpleImputer(missing_values = np.nan, strategy = 'most_frequent')

imputerN = imputerN.fit(df[col_n])
df[col_n] = imputerN.transform(df[col_n])
imputerC = imputerC.fit(df[col_c])
df[col_c] = imputerC.transform(df[col_c])

# ## tratar os tipos object

df.get_dtype_counts()

for c in df.columns:
    if df[c].dtypes == 'object':
        print(c,df[c].unique())

# Para os dados categóricos existem diversas abordagens, a mais comum é a conversão para pseudo-inteiros ou a one-hot.

for c in df.columns:
    if df[c].dtype.name == "object":
        df[c] = df[c].astype('category')

#conversao para pseudo atributos inteiros
for c in df.columns:
    if df[c].dtypes.name == 'category':
        df[c] = df[c].cat.codes


def pre_process(df):
    df.PoolQC.fillna('NtE', inplace=True)
    df.Fence.fillna('NtE', inplace=True)
    df.FireplaceQu.fillna('NtE', inplace=True)
    df.MiscFeature.fillna('None', inplace=True)
    df.Alley.fillna('None', inplace=True)
    
    miss = missing_values_table(df)
    
    col_n = []
    col_c = []
    for c in miss.index:
        #print(c,df[c].dtypes,df[c].unique())
        if df[c].dtypes == 'object':
            col_c.append(c)
        else:
            col_n.append(c)
            
    imputerN = SimpleImputer(missing_values = np.nan, strategy = 'mean')
    imputerC = SimpleImputer(missing_values = np.nan, strategy = 'most_frequent')
    
    imputerN = imputerN.fit(df[col_n])
    df[col_n] = imputerN.transform(df[col_n])
    imputerC = imputerC.fit(df[col_c])
    df[col_c] = imputerC.transform(df[col_c])
    
    for c in df.columns:
        if df[c].dtype.name == "object":
            df[c] = df[c].astype('category')
            
    #conversao para pseudo atributos inteiros
    for c in df.columns:
        if df[c].dtypes.name == 'category':
            df[c] = df[c].cat.codes
    
    return df


# ## Visualização

from mpl_toolkits.mplot3d import Axes3D
from sklearn import decomposition
import seaborn as sn

df2 = df[df.columns.difference(['SalePrice','Id'])].copy()


def pca_view(df2, n_components=4):
    pca = decomposition.PCA(n_components=n_components)
    pca.fit(df2)
    X = pca.transform(df2)
    print("Soma dos 3 primeiros componentes:",np.sum(pca.explained_variance_ratio_[0:3]))
    
    sn.barplot(list(range(1,len(pca.components_)+1)), 1*pca.explained_variance_ratio_)
    plt.plot(np.cumsum(pca.explained_variance_ratio_), )
    plt.show()
    
    fig = plt.figure(1, figsize=(10, 10))
    plt.clf()
    ax = Axes3D(fig, rect=[0, 0, .95, 1], elev=18, azim=134)
    plt.cla()
    ax.scatter(X[:, 0], X[:, 1], X[:, 2], edgecolor='k')
    ax.w_xaxis.set_ticklabels([])
    ax.w_yaxis.set_ticklabels([])
    ax.w_zaxis.set_ticklabels([])
    
    fig = plt.figure(figsize = (8,8))
    ax = fig.add_subplot(1,1,1) 
    ax.set_xlabel('Componente Principal 1', fontsize = 15)
    ax.set_ylabel('Componente Principal 2', fontsize = 15)

    ax.scatter(X[:, 0], X[:, 1], s = 50)
    plt.show()
    
    return X


df2.boxplot(figsize=(20, 20), rot=90)

# #### Em alguns atributos, é possível dectectar a presença de outiliers, nesse caso é necessário um pouco de atenção e verificar a necessidade de normalizar os dados.

from sklearn.preprocessing import StandardScaler, RobustScaler, Normalizer, QuantileTransformer, MinMaxScaler

x_st = StandardScaler().fit_transform(df2)

print("Normalizados:")
pca_view(x_st, 10) # normalizado
print("Dados originais:")
pca_view(df2, 10) # dados reais

# ### Aparentemente a disposição dos dados está mais para não linear do que uma apresentação linear, conforme visto anteriormente na técnica PCA, vou confirmar isso também utilizando um SVM sem kernel.

from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
from sklearn.ensemble import RandomForestRegressor, GradientBoostingRegressor
from sklearn.svm import LinearSVR, SVR
from sklearn.neural_network import MLPRegressor
from sklearn.model_selection import train_test_split, cross_val_score, cross_validate
import sklearn
import xgboost

X = df2
y = df['SalePrice'].values

X_train, X_test, y_train, y_test = train_test_split(df2, y, train_size=0.75, test_size=0.25)

svm_lin = LinearSVR(max_iter=20000, epsilon=0.1)
svm_lin.fit(X_train, y_train)
print(svm_lin.score(X_test, y_test)) 
print("R2",cross_val_score(svm_lin, X_test, y_test, cv=5, scoring='r2'))





# ## RandomForest

rf = RandomForestRegressor()
rf.fit(X_train, y_train)
print(rf.score(X_test, y_test))
print("R2",cross_validate(rf, X, y, cv=5, scoring=('r2')))



# ## GradientBoosting

gb = GradientBoostingRegressor()
gb.fit(X_train, y_train)
print(gb.score(X_test, y_test))
print("R2",cross_validate(gb, X, y, cv=5, scoring=('r2')))

# ## XGBoost

xgb = xgboost.XGBRegressor()
xgb.fit(X_train, y_train)
print(xgb.score(X_test, y_test))
print("R2",cross_validate(xgb, X, y, cv=5, scoring=('r2')))



# ## MLP

mlp = MLPRegressor(hidden_layer_sizes=(200,), max_iter=1000, alpha=0.5)
mlp.fit(X_train, y_train)
print(mlp.score(X_test, y_test))
print("R2",cross_validate(mlp, X, y, cv=5, scoring=('r2')))



# #### Até agora, as técnicas XGBoost, GB, RF e SVM linear estão apresentando uma melhor performance

# A próxima abordagem é ajustar os hiper parâmetros, geralmente o comum é utilizar um técnica de GridSearch.

from sklearn.model_selection import RandomizedSearchCV, GridSearchCV

params = {
        'min_child_weight': [1, 5, 10, 20, 30],
        'gamma': [0.5, 1, 1.5, 2, 5, 10, 20, 30, 40, 50, 90, 100, 150],
        'subsample': [0.6, 0.8, 1.0],
        'colsample_bytree': [0.6, 0.8, 1.0],
        'max_depth': [3, 4, 5, 10, 15, 50]
        }
param_comb = 5

params = {
        'min_child_weight': [1, 5, 10],
        'gamma': [0.5, 1, 1.5, 2, 5],
        'subsample': [0.6, 0.8, 1.0],
        'colsample_bytree': [0.6, 0.8, 1.0],
        'max_depth': [3, 4, 5]
        }

random_search = RandomizedSearchCV(xgb, param_distributions=params, n_iter=param_comb, scoring='r2', n_jobs=4, cv=5, random_state=1001 )

random_search.fit(X_train, y_train)

print('\n All results:')
print(random_search.cv_results_)
print('\n Best estimator:')
print(random_search.best_estimator_)
print('\n Best normalized gini score for %d-fold search with %d parameter combinations:' % (5, param_comb))
print(random_search.best_score_ * 2 - 1)
print('\n Best hyperparameters:')
print(random_search.best_params_)

results_hp = cross_validate(random_search.best_estimator_, X, y, cv=5, scoring=('r2'))

results_nm = cross_validate(xgb, X, y, cv=5, scoring=('r2'))

print("XGB BH:", np.mean(results_hp['test_score']))
print("XGB NM:", np.mean(results_nm['test_score']))



fig, ax = plt.subplots(figsize=(20, 20))
xgboost.plot_importance(random_search.best_estimator_, ax=ax)



test_df = pd.read_csv('data/test.csv')

test_df = pre_process(test_df)

test_df2 = test_df[test_df.columns.difference(['Id'])].copy()

pca_view(test_df2)

y_test = xgb.predict(test_df2)



results_df = pd.DataFrame(data={'Id':test_df['Id'], 'SalePrice':y_test})
results_df.to_csv('submission-xgb-01.csv', index=False)



StarcoderdataJupyterScriptsDedupFiltered