<jupyter_start><jupyter_text>**Visualizar quantas linhas temos em cada coluna utilizando o código acima nos permitirá saber se temos um dataset balanceado, ou seja, quando temos uma quantidade semelhante de linha para cada classe de nosso DataFrame (Y e N, no caso)**<jupyter_code># O gráfico abaixo irá gerar um gráfico para cada uma das colunas e mostrará como está a distribuição
# de renda (Applicant Income) 
df[['Loan_Status','ApplicantIncome']].hist(by='Loan_Status', figsize=(17,7), bins=50)
plt.show()<jupyter_output><empty_output><jupyter_text>**O gráfico acima nos mostra que, pelo menos, 80% das pessoas que pediram um empréstimo tem renda de até U$ 20 mil, independente se eles foram aprovados ou não.**  Feature EngineeringVamos trabalhar algumas *features* para que elas possam ser interpretadas por nosso modelo. Por exemplo, sabemos que modelos somente entendem **colunas numéricas**, e nós temos muitas colunas categóricas. Vamos transformá-las nas células abaixo.<jupyter_code># Renomeando colunas
df.columns = ['Loan_ID', 'is_Male', 'is_Married', 'Dependents', 'is_Graduated',
              'is_Self_Employed', 'ApplicantIncome', 'CoapplicantIncome', 'LoanAmount',
              'Loan_Amount_Term', 'Credit_History', 'Property_Area', 'Loan_Status']
# Vamos usar o map para que possamos alterar os valores de YES ou NO para binários
yes_no_map = {'Yes': 1, 'No': 0}
df['is_Married'] = df['is_Married'].map(yes_no_map)
# Vamos criar uma coluna que contém o Total de renda dos aplicante, 
# somando as colunas ApplicantIncome e CoapplicantIncome
df['TotalIncome'] = df['ApplicantIncome'] + df['CoapplicantIncome']
# Por fim, vamos mappear a coluna que queremos prever 
mapper_status = {'Y': 1,
                 'N': 0}
df['Loan_Status'] = df['Loan_Status'].map(mapper_status)
# Primeiras linhas do novo DataFrame
df.head()<jupyter_output><empty_output><jupyter_text>Data CleaningExistem muitas formas de lidar com dados nulos (*missing data*). Abaixo irei mostrar algumas técnicas que você pode utilizar. É interessante que, após treinar seu modelo pela primeira vez, você volte nessas fases e tente limpar seus dados de outras formas.<jupyter_code># Vamos ver quantos valores nulos tem em cada coluna
df.isnull().sum().sort_values(ascending=False)
# A coluna is_Married possui apenas 3 valores nulos. Irei desconsiderar essas linhas.
# Vamos utilizar a função .loc para selecionar todas as linhas que não contém dados nulos na coluna is_Married
df = df.loc[df['is_Married'].notnull()]
# Também podemos preencher valores nulos com a média.
# Aqui, vamos preencher a coluna LoanAmount com a média
df['LoanAmount'].fillna(df['LoanAmount'].mean(), inplace=True)
# De forma semelhante aos anteriores, vamos preencher o valor da coluna Credit_History
# com o valor mais frequente
df['Credit_History'].value_counts()
df['Credit_History'].fillna(1, inplace=True)<jupyter_output><empty_output><jupyter_text>Feature SelectionFeature Selection é o ato de você selecionar as melhores *features* do DataFrame para enviar para o modelo. Aqui essa fase será bem curta, onde apenas iremos remover a coluna `Loan_ID`, mas você pode sempre voltar nessa fase e **colocar e remover outras colunas para ver se seu modelo performa melhor**.<jupyter_code># Vamos remover a coluna Loan_ID
# A função .drop() fará isso. o argumento axis=1 informa que queremos remover a coluna inteira
# O argumento inplace=True evita que nós utilizemos o código df = df.drop(...)
# Ou seja, ele irá salvar a alteração direto no DataFrame
df.drop('Loan_ID', axis=1, inplace=True)<jupyter_output><empty_output><jupyter_text>One-hot EncodingExiste uma técnica de codificação de feature chamada **One-hot Encoding**, que irá gerar uma coluna para cada valor distinto na coluna que você quer codificar.Por exemplo, imagine que você tem uma coluna chamada **Color**, que possui três valores distintos: **Red** (Vermelho), **Yellow** (Amarelo) e **Green** (Verde). Se você aplica o **One-hot Encoding** na coluna **Color**, o Python irá gerar três novas colunas, chamadas: **is_Red**, **is_Yellow** e **is_Green**, e irá marcar com o valor `1` onde esse valor for compatível. A imagem abaixo exemplifica esse processo:![](https://i.imgur.com/mtimFxh.png)<jupyter_code># Vamos aplicar o One-hot Encoding na coluna Property Area, que criará uma coluna para cada valor distinto presente
# na coluna: Rural, Semiurban e Urban
df = pd.get_dummies(df, columns=['Property_Area'])
# Vamos conferir novamente como o Pandas está interpretando cada coluna
df.dtypes<jupyter_output><empty_output><jupyter_text>CorrelaçãoA correlação procura entender como duas variáveis se movem em conjunto, tanto positiva quanto negativamente. Um exemplo de correlação positiva é dizermos que **quanto mais horas um aluno estuda, maior é a nota que ele tira**, ou então dizermos que **quanto maior a altura dos pais, maior será a altura dos filhos**. Um fato importante sobre a correlação é que ela ser alta ou baixa não representa **causalidade**. Por exemplo, não é por causa que um aluno estudou 20 horas que ele irá uma nota maior, outros fatores são importantes para se analisar. A correlação nos ajudará a entender se essas duas variáveis andam juntas (e como andam).<jupyter_code># No Pandas, podemos utilizar a função .corr() para verificar a correlação de um DataFrame
df.corr()
# Para melhorar a visualização, podemos criar um mapa de calor
plt.figure(figsize=(17,10))
sns.heatmap(df.corr(), annot=True, fmt='.2f')
plt.title('Correlação das variáveis do DataFrame')
plt.show()<jupyter_output><empty_output><jupyter_text>Treinando o modelo<jupyter_code># Normalizando coluna que possuem uma dispersão muito alta
df['ApplicantIncome'] = np.log(df['ApplicantIncome'])
df['TotalIncome'] = np.log(df['TotalIncome'])<jupyter_output><empty_output><jupyter_text>Dividindo conjuntos de treino e teste<jupyter_code># Criando variáveis com nossas features
X = df.drop('Loan_Status', axis=1)
# Criando variável com coluna que queremos prever
y = df['Loan_Status']
# Criando conjuntos de treino e teste
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=42)<jupyter_output><empty_output><jupyter_text>Testando diferentes modelos<jupyter_code># Vamos começar treinando uma Regressão Logística
lr = LogisticRegression()
lr.fit(X_train, y_train)

print('Score conjunto de treino: {0:.2%}'.format(lr.score(X_train, y_train)))
print('Score conjunto de teste: {0:.2%}'.format(lr.score(X_test, y_test)))
# Podemos testar também outros modelos, como uma Arvore de Decisão simples
dt = DecisionTreeClassifier()
dt.fit(X_train, y_train)

print('Score conjunto de treino: {0:.2%}'.format(dt.score(X_train, y_train)))
print('Score conjunto de teste: {0:.2%}'.format(dt.score(X_test, y_test)))
# O modelo acima gerou ovefitting em nosso treino (quando o modelo aprende muito bem o conjunto de treino, mas não é bom para entender novos casos)
dt = DecisionTreeClassifier(max_depth=4)
dt.fit(X_train, y_train)

print('Score conjunto de treino: {0:.2%}'.format(dt.score(X_train, y_train)))
print('Score conjunto de teste: {0:.2%}'.format(dt.score(X_test, y_test)))
# Por fim, vamos tentar uma Random Forest para ver se nosso modelo performa melhor
rf = RandomForestClassifier()
rf.fit(X_train, y_train)

print('Score conjunto de treino: {0:.2%}'.format(rf.score(X_train, y_train)))
print('Score conjunto de teste: {0:.2%}'.format(rf.score(X_test, y_test)))<jupyter_output>Score conjunto de treino: 99.27%
Score conjunto de teste: 76.24%
{'fraction_non_alphanumeric': 0.09978655282817503, 'fraction_numerical': 0.007470651013874066, 'mean_word_length': 6.032833020637899, 'pattern_counts': {'":': 0, '<': 36, '<?xml version=': 0, '>': 36, 'https://': 1, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '9', 'dir': 'jupyter-structured-clean-dedup', 'id': '533681', 'license': 'MIT', 'n_tokens_mistral': 2712, 'n_tokens_neox': 2605, 'n_words': 873, 'path': 'projeto_emprestimo/loan_prediction.ipynb', 'repo_name': 'brunob182/python-data-analysis', 'size': '7496'}