"""
        N ºUsp: 11871326
        Data: 08/09/2020
"""
"""
# Primeiramente, importaremos tudo o que vamos precisar:
"""
import pandas as pd
import sklearn
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import cross_val_score
from sklearn.metrics import classification_report, confusion_matrix, accuracy_score
from sklearn import preprocessing as prep
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap
import numpy as np
"""
# Em seguida, importamos os dados do csv:
"""
nomes = ["Age", "Workclass", "fnlwgt", "Education", "Education-Num", "Martial Status",
            "Occupation", "Relationship", "Race", "Sex", "Capital Gain", "Capital Loss",
            "Hours per week", "Country", "Target"]

train_data = pd.read_csv("../input/adult-pmr3508/train_data.csv", names = nomes,
        sep= r'\s*,\s*',
        engine= 'python',
        na_values= "?")

train_data = train_data.iloc[1:]
train_data.shape
train_data.head()
nomes = ["Id", "Age", "Workclass", "fnlwgt", "Education", "Education-Num", "Martial Status",
            "Occupation", "Relationship", "Race", "Sex", "Capital Gain", "Capital Loss",
            "Hours per week", "Country", "Target"]
test_data = pd.read_csv("../input/adult-pmr3508/test_data.csv", names = nomes,
        sep= r'\s*,\s*',
        engine= 'python',
        na_values= "?")

test_data.shape
test_data.head()
"""
# Agora vamos analizar os dados, através de graficos, para ver quais devem ser descartados para a predição:  
"""
plt.title('Age')
plt.ylabel('Adults')
plt.xlabel('Age')
plot_data = train_data["Age"].value_counts()
plot_data.plot(kind = "line", sharex=False)
#plt.legend()
plt.show()
plot_data = train_data["Workclass"].value_counts().copy()
plot_data.plot(kind = "bar", fontsize=12)
plt.title('Workclass')
plt.ylabel('Adults')
plt.show()
plot_data = train_data["Education"].value_counts().copy()
plot_data.plot(kind = "bar", fontsize=10)
plt.title('Education')
plt.ylabel('Adults')
plt.show()
"""
Vale notar aqui que há uma versão numrica desssa feature, "Education-Num" que será mais util na predição
"""
plot_data = train_data["Martial Status"].value_counts().copy()
plot_data.plot(kind = "bar")
plt.title('Martial Status')
plt.ylabel('Adults')
plt.show()

plot_data = train_data["Occupation"].value_counts().copy()
plot_data.plot(kind = "bar", fontsize=10)

plt.title('Occupation')
plt.ylabel('Adults')
plt.show()
plot_data = train_data["Relationship"].value_counts().copy()
plot_data.plot(kind = "pie", fontsize=8, ylabel="")
plt.title('Relationship')
plt.show()
plot_data = train_data["Race"].value_counts().copy()
plot_data.plot(kind = "pie", legend=True, fontsize=0, ylabel="")

plt.title('Race')
plt.show()
plot_data = train_data["Sex"].value_counts().copy()
plot_data.plot(kind = "pie", ylabel="", autopct='%1.0f%%', radius=1)

plt.title('Sex')
plt.show()
plot_data = train_data["Country"].value_counts().copy()

us_data = plot_data[0]
mex_data = plot_data[1]
others_data = 0
i = 2
while i < len(plot_data): 
    others_data += plot_data[i]
    i += 1
    
x = ['United States', 'Mexico','Others']
y = [us_data, mex_data, others_data]

plt.bar(x, y)
plt.title('Countries (US | Mex | Others)')
plt.show()
    
plot_data.iloc[2:].plot(kind = "bar", fontsize=8)

plt.title('Countries (Others)')
plt.ylabel('Adults')
plt.show()
"""
**Conclusões:**
1. A feature "Country" deve ser descartada, uma vez que US é a esmagadora maioria     
2. A feature "fnlwgt", por não ter nenhuma constância ou relação com a predição, também será descartada
3. Será utilizada a feature "Education-Num" e não a "Education", pois já está com valores numéricos
"""
"""
# Compararemos agora alguns dados em relação à feature "income":
"""
def bar_plot(data, hue, by="Target", size=20, normalize_by_index = True):
    index = data[by].unique()
    
    columns = data[hue].unique()
  
    data_to_plot = pd.DataFrame({'index': index})
    
    for column in columns:
        temp = []
        for unique in index:
            filtered_data = data[data[by] == unique]
            filtered_data = filtered_data[filtered_data[hue] == column]
            
            temp.append(filtered_data.shape[0])
        data_to_plot = pd.concat([data_to_plot, pd.DataFrame({column: temp})], axis = 1)
        
    data_to_plot = data_to_plot.set_index('index', drop = True)
    
    if normalize_by_index:
        for row in index:
            data_to_plot.loc[row] = data_to_plot.loc[row].values/data_to_plot.loc[row].values.sum()
    
    ax = data_to_plot.plot.bar(rot=0, figsize = (14,7), alpha = 0.9, cmap = 'Wistia', xlabel="", fontsize=size)
bar_plot(train_data, 'Education')
bar_plot(train_data, 'Race')
bar_plot(train_data, 'Sex')
"""
Ao comparar as features "Race" e "Sex" com "income", é possível perceber as desigualdades existentes entre brancos e negros e homens e mulheres na questão da renda. Já na feature "Education" pode-se notar que a renda é de certa forma distribuida proporcionalmente à quantidade de cada grupo, e não que quanto mais estudo maior a renda, como muitos pensam.
"""
"""
# Analizemos agora os dados faltantes:
"""
train_data.isnull().sum()
"""
Nota-se que as features "Workclass", "Occupation" e "Country" concentram os dados faltantes

# Assim, iremos substituir esses dados pela moda nas respectivas features:
"""
moda_workclass = train_data['Workclass'].describe().top
train_data['Workclass'] = train_data['Workclass'].fillna(moda_workclass)

moda_occupation = train_data['Occupation'].describe().top
train_data['Occupation'] = train_data['Occupation'].fillna(moda_occupation)

moda_country = train_data['Country'].describe().top
train_data['Country'] = train_data['Country'].fillna(moda_country)
moda_workclass = test_data['Workclass'].describe().top
test_data['Workclass'] = test_data['Workclass'].fillna(moda_workclass)

moda_occupation = test_data['Occupation'].describe().top
test_data['Occupation'] = test_data['Occupation'].fillna(moda_occupation)

moda_country = test_data['Country'].describe().top
test_data['Country'] = test_data['Country'].fillna(moda_country)
"""
# Nesse momento transformaremos os dados não-numéricos em dados numéricos:
"""
train_data = train_data.apply(prep.LabelEncoder().fit_transform)
test_data = test_data.apply(prep.LabelEncoder().fit_transform)

train_data.head()

"""
# Nesse ponto vamos dividir os dados em X e Y para posteriormente colocá-los no classificador:
"""
features = ["Age", "Workclass", "Education", "Occupation", "Race", "Capital Gain", "Capital Loss", "Hours per week"]

x_train = train_data[features]
y_train = train_data.Target

x_test = test_data[features]
y_test = test_data.Target
"""
# Fazemos então a validação cruzada desses dados:
"""
knn = KNeighborsClassifier(n_neighbors = 5)

scores = cross_val_score(knn, x_train, y_train, cv=10)
scores.mean()
"""
# Encontraremos o melhor valor para o hyperparâmetro K: 
"""
inf = 1
sup = 35

scores_media = []
aux = 0
k_max = 0

i = 0
for k in range(inf, sup):
    knn = KNeighborsClassifier(n_neighbors = k)
    scores = cross_val_score(knn, x_train, y_train, cv=10)
    scores_media.append(scores.mean())

    if scores_media[i] > aux:
        k_max = k
        aux = scores_media[i]

    i = i + 1

x = np.arange(1, sup)

knn = KNeighborsClassifier(n_neighbors = k_max)

scores = cross_val_score(knn, x_train, y_train, cv=10)
y = scores.mean()

plt.figure(figsize=(10, 5))
plt.plot(x, scores_media, '--', color = 'red', linewidth = 2)
plt.plot(k_max, y, 'o')

plt.xlabel('K')
plt.ylabel('Acurácia')
plt.title('Acurácia da predição  X  Valor de K')

print(k_max)
"""
Assim, vimos que o valor ideal para K é 20
"""
"""
# Finalmente, colocaremos esses dados no classificador Knn e observar sua acurácia:
"""
knn = KNeighborsClassifier(n_neighbors = 20)

scores = cross_val_score(knn, x_train, y_train, cv=10)
score = scores.mean()

print('Acurácia para k = {0} : {1:2.2f}%'.format(k_max, 100 * score))
knn.fit(x_train, y_train)
predict_knn = knn.predict(x_test)
"""
# Portanto, após analizar e preparar os dados e treiná-los no modelo KNN, obtivemos como melhor resultado 81% de acurácia na predição, o que é um valor bastante aceitável no caso.
"""
"""
# Finalmente, vamos transformar de volta os valores numéricos da feature "Income" a <=50K e >50K
# Então escreveremos a predição no csv:
"""
valores_originais = {0: '<=50K', 1: '>50K'}
predicao = np.array([valores_originais[i] for i in predict_knn], dtype=object)

submission = pd.DataFrame()

print(len(test_data.index), len(predicao))

submission[0] = test_data.index
submission[1] = predicao
submission.columns = ['Id', 'Income']

submission.to_csv('final_results.csv',index = False)