National Institute of Diabetes and Digestive and Kidney Diseases

26 de agosto, 2020

1. Descrição geral do problema


Diabetes

Diabetes é uma síndrome metabólica que acontece pela falta de insulina e/ou pela incapacidade da insulina exercer adequadamente seus efeitos, causando um aumento da glicose (açúcar) no sangue.

A diabetes acontece, porque o pâncreas não é capaz de produzir insulina em quantidade suficiente para suprir as necessidades do organismo, ou porque este hormônio não é capaz de agir de maneira adequada (resistência à insulina).

A insulina promove a redução da glicemia ao permitir que o açúcar que está presente no sangue possa penetrar dentro das células, para ser utilizado como fonte de energia.

Portanto, se houver falta desse hormônio ou mesmo se ele não agir corretamente, haverá aumento de glicose (açúcar) no sangue e, consequentemente, o diabetes.

O conjunto de dados é do Instituto Nacional de Diabetes e Doenças Digestivas e Renais (National Institute of Diabetes and Digestive and Kidney Diseases). Várias restrições foram colocadas na seleção dessas instâncias de um banco de dados maior. Em particular, todos os pacientes aqui são do sexo feminino com pelo menos 21 anos de idade.

Objetivo: Utilizar a linguagem Python, para prever com base em medidas de diagnóstico, se um paciente tem diabetes.


2. Carregando Dados

2.1 Importando bibliotecas necessárias

Começaremos nosso projeto, importanto todas as bilbiotecas necessárias, para a realização das fases iniciais de exploração, e transformação dos dados (Data Munging).

In [1]:
# Importando biblioteca, para ocultar Future Warnings.

import warnings

warnings.simplefilter(action = 'ignore', category = FutureWarning)

# Importando bibliotecas, para a manipulação e exploração dos conjuntos de dados.

import numpy as np

import pandas as pd

# Importando bibliotecas, para tarefas de Data Munging.

from sklearn.feature_selection import VarianceThreshold

# Importando bibliotecas, para a plotagem de gráficos interativos com o plotly.

import plotly.offline as py

import plotly.graph_objs as go

import plotly.figure_factory as ff

py.init_notebook_mode(connected = False)

# Importando bibliotecas, para a plotagem de gráficos com o Seaborn e Matplotlib.

import seaborn as sns

import matplotlib.pyplot as plt

# Importando classes e bibliotecas, para a etapa de pré-processamento dos dados.

from sklearn import preprocessing

from sklearn.preprocessing import MinMaxScaler, PowerTransformer, normalize, LabelEncoder, StandardScaler

# Importando classes para calcular algumas estatísticas.

from scipy.stats import kurtosis, skew

# Importando biliotecas, para a fase de Feature Selection.

from sklearn.decomposition import PCA

from mlxtend.feature_selection import SequentialFeatureSelector as SFS

from sklearn.feature_selection import SelectKBest, SelectPercentile, mutual_info_classif, f_classif, RFE, chi2

# Importando bibliotecas, para a etapa de modelagem preditiva.

import xgboost as xgb

from sklearn import tree

from sklearn.svm import SVC

from sklearn.naive_bayes import GaussianNB

from sklearn.tree import DecisionTreeClassifier

from sklearn.neighbors import KNeighborsClassifier

from sklearn.linear_model import LogisticRegression, RidgeClassifierCV

from sklearn.model_selection import KFold, cross_val_score, train_test_split

from sklearn.discriminant_analysis import LinearDiscriminantAnalysis, QuadraticDiscriminantAnalysis

from sklearn.ensemble import RandomForestClassifier, ExtraTreesClassifier, AdaBoostClassifier, GradientBoostingClassifier

# Importando Classe, para carregar e salvar modelos preditivos em arquivos externos.

import pickle

# Importando Classe, para fazer a busca dos melhores parâmetros, a serem utilizados em cada um dos modelos treinados.

from sklearn.model_selection import GridSearchCV

# Importando Classes, para calcular as métricas de avaliação dos modelos preditivos.

from sklearn.metrics import accuracy_score, balanced_accuracy_score, average_precision_score, precision_score
from sklearn.metrics import recall_score, f1_score, roc_auc_score, cohen_kappa_score

2.2 Carregando Dados

In [2]:
# Definindo o nome das colunas do dataset.

names = ['id', 
         'num_gestacoes', 
         'glicose', 
         'pressao_sanguinea', 
         'grossura_pele', 
         'insulina', 
         'bmi', 
         'indice_historico', 
         'idade', 
         'diabetes']

# Carregando conjunto de dados.

data = pd.read_csv('content/datasets/diabetes.csv', names = names)
In [3]:
# Exibindo as primeiras linhas do DataFrame.

data.head()
Out[3]:
id num_gestacoes glicose pressao_sanguinea grossura_pele insulina bmi indice_historico idade diabetes
0 1 6 148 72 35 0 33.6 0.627 50 1
1 2 1 85 66 29 0 26.6 0.351 31 0
2 3 8 183 64 0 0 23.3 0.672 32 1
3 4 1 89 66 23 94 28.1 0.167 21 0
4 5 0 137 40 35 168 43.1 2.288 33 1

3. Data Munging - Preparando dados para a análise exploratória

Antes de prosseguirmos, é importante destacar a informação que cada variável representa:

Variável Tipo Descrição
id int64 É o identificador do registro;
num_gestacoes int64 É o número de vezes grávida;
glicose int64 É a concentração plasmática de glicose em teste oral de tolerância à glicose;
pressao_sanguinea int64 É a pressão arterial diastólica em mmHg;
grossura_pele int64 É a espessura da dobra da pele do tríceps em mm;
insulina int64 É a insulina em µU/ml;
bmi float64 É o índice de massa corporal medido em peso em $kg / [altura (m)] ^ 2$;
indice_historico float64 É o índice de histórico de diabetes (Pedigree Function);
idade int64 É a idade em anos e;
diabetes (Target) int64 É a variável que indica se a mulher tem diabetes. (0 - não desenvolveu a doença / 1 - desenvolveu a doença)

3.1 Visão geral dos dados

In [4]:
# Verificando as dimensões do dataset.

data.shape
Out[4]:
(768, 10)

Verificamos a existência de 10 variáveis, e 768 observações dentro do dataset.

In [5]:
# Verificando o número de registros duplicados.

data.duplicated().sum()
Out[5]:
0

Não há registros duplicados dentro do conjunto de dados.

In [6]:
# Verificando o número de NAs existentes dentro do dataset.

data.isna().sum()
Out[6]:
id                   0
num_gestacoes        0
glicose              0
pressao_sanguinea    0
grossura_pele        0
insulina             0
bmi                  0
indice_historico     0
idade                0
diabetes             0
dtype: int64

Não há valores nulos dentro do conjunto de dados.

In [7]:
# Verificando o tipo de dados das variáveis do dataset.

data.dtypes.value_counts()
Out[7]:
int64      8
float64    2
dtype: int64

Todas as variáveis do conjunto de dados, foram classificadas como sendo do tipo de dado numérico.

In [8]:
# Contabilizando o número de valores únicos em cada variável do dataset.

info = data.nunique().sort_values()

# Determinando o tipo de dado de cada uma das variáveis do dataset.

info = pd.DataFrame(info.values, index = info.index, columns = ['NUniques'])

# Atribuindo informações sobre o tipo de dado das variáveis ao DataFrame.

info['dtypes'] = data.dtypes

# Exibindo Dataframe.

info
Out[8]:
NUniques dtypes
diabetes 2 int64
num_gestacoes 17 int64
pressao_sanguinea 47 int64
grossura_pele 51 int64
idade 52 int64
glicose 136 int64
insulina 186 int64
bmi 248 float64
indice_historico 517 float64
id 768 int64

Todas as variáveis preditoras, apresentam um grande número de valores únicos.

3.2 Eliminando variáveis desnecessárias

In [9]:
# Eliminando a variável id do conjunto de dados.

data = data.drop('id', axis = 1)

3.3 Convertendo variável target para o tipo de dado categórico

In [10]:
# Atribuindo labels diferentes para as categorias da variável target.

data['diabetes'] = ['Yes' if v == 1 else 'No' for v in data['diabetes']]

# Alterando a variável target para o tipo de dado categórico.

data['diabetes'] = data['diabetes'].astype('category')

4. Análise exploratória dos dados

4.1 Criando funções auxiliares

Iremos definir algumas funções, para padronizar as plotagens de gráficos que criaremos.

4.1.1 Para a plotagem de gráficos interativos

Para fazer plotagens offline com o plotly (isto é, em ambientes como o Google Colab, Azure, Kaggle, Nteract, etc.), precisamos definir a função a seguir, e chamá-la sempre que formos gerar um gráfico.

In [11]:
# Definindo uma função, para plotar gráficos interativos, em um ambiente jupyter não-padrão.

def configure_plotly_browser_state():
  
  import IPython
  
  display(IPython.core.display.HTML('''
        <script src="/static/components/requirejs/require.js"></script>
        <script>
          requirejs.config({
            paths: {
              base: '/static/base',
              plotly: 'https://cdn.plot.ly/plotly-1.43.1.min.js?noext',
            },
          });
        </script>
        '''))

4.1.2 Gráficos de Distribuição

Os gráficos de distribuição são usados para mostrar como as variáveis são distribuídas ao longo do tempo, ajudando a identificar valores discrepantes e tendências.

In [12]:
# Definindo uma função, para criar gráficos de Boxplot interativos com o plotly.

def plotBoxplot(data, name = '', col = '', target = '', title = '', yaxis = '', xaxis = '', kind = 'normal',
                color = ['#8783D1', '#FADF63', '#06D6A0', '#662E9B'], opacity = 0.65, template = 'plotly_white', 
                orientation = 'v'):
    
    # Realizando as pré-configurações necessárias, para a plotagem do gráfico interativo.

    configure_plotly_browser_state()

    # Plota gráficos de um ou mais boxplots simples.

    if kind == 'normal': 

        # Plota gráficos verticais.

        if orientation == 'v':

            # Definindo os dados, a cor, o nome e a transparência que serão utilizados para criar cada um dos Boxplots.
            
            dataTrace = [
                go.Box(
                    y      = data[l], 
                    name   = l if name == '' else name, 
                    marker = {'color': color[2], "opacity": opacity}) 
                for l in data.columns
            ]
        
        # Plota gráficos horizontais.

        else:

            # Definindo os dados, a cor, o nome e a transparência que serão utilizados para criar cada um dos Boxplots.

            dataTrace = [
                go.Box(
                    x      = data[l], 
                    name   = l if name == '' else name, 
                    marker = {'color': color[3], "opacity": opacity}) 
                for l in data.columns
            ]

    # Plota gráficos boxplot, para uma variável numérica, agrupada por uma variável categórica.

    elif kind == 'groups':
        
        # Captura os registros pertencentes a cada categoria, da variável categórica.

        g = [data[data[target] == cat] for cat in data[target].cat.categories]

        # Converte a primeira letra do nome de cada categoria para maiúscula.

        name = [n.capitalize() for n in data[target].cat.categories]

        # Plota gráficos verticais.

        if orientation == 'v':
            
            # Definindo os dados, a cor, o nome e a transparência que serão utilizados para criar cada um dos Boxplots.

            dataTrace = [
                go.Box(
                    y      = g[l][col], 
                    name   = name[l], 
                    marker = {'color': color[l], "opacity": opacity}) 
                for l in range(0, len(g))
            ]
        
        # Plota gráficos horizontais.

        else:

            # Definindo os dados, a cor, o nome e a transparência que serão utilizados para criar cada um dos Boxplots.

            dataTrace = [
                go.Box(
                    x      = g[l][col], 
                    name   = name[l], 
                    marker = {'color': color[l], "opacity": opacity}) 
                for l in range(0, len(g))
            ]
    
    # Defindo as configurações de layout.

    layout = go.Layout (
        title    = title,
        yaxis    =  {'title': yaxis},
        xaxis    =  {'title': xaxis},
        template = template
    )

    # Criando uma Figure, com os dados e o layout defindos.

    fig = go.Figure(data = dataTrace, layout = layout)

    # Plotando o Figure com o pyplot.

    py.iplot(fig)
In [13]:
# Definindo uma função, para criar Histogramas interativos com o plotly.

def plotHist(data, col = '', target = '', title = '', yaxis = '', xaxis = '', 
             groups = False, color = ['#8783D1', '#FADF63', '#EF476F'], opacity = 0.65, 
             template = 'plotly_white'):
    
    # Realizando as pré-configurações necessárias, para a plotagem do gráfico interativo.

    configure_plotly_browser_state()
    
    # Criando um histograma para um conjunto de dados.

    if groups == False:

        # Definindo os dados, a cor, e a transparência que serão utilizados para criar o Histograma.

        dataTrace = go.Histogram(x = data, marker = {'color': color[2], "opacity": opacity})

    # Criando um histograma para um conjunto de dados agrupado por categorias.

    else:
        
        # Captura os registros pertencentes a cada categoria, da variável categórica.

        g = [data[data[target] == cat] for cat in data[target].cat.categories]

        # Definindo os dados, a cor, e a transparência que serão utilizados para criar cada um dos Histogramas.

        dataTrace = [
            go.Histogram(
                x      = g[cat][col], 
                name   = data[target].cat.categories[cat].capitalize(), 
                marker = {'color': color[cat], "opacity": opacity}) 
            for cat in range(0,len(g))
        ]

    # Defindo as configurações de layout.

    layout = go.Layout(
        title    = title,
        yaxis    =  {'title': yaxis},
        xaxis    =  {'title': xaxis},
        bargap   = 0.05,
        template = template
    )

    # Criando uma Figure, com os dados e o layout defindos.

    fig = go.Figure(data = dataTrace, layout = layout)

    # Plotando o Figure com o pyplot.

    py.iplot(fig)
In [14]:
# Definindo uma função, para criar gráficos de Densidade interativos com o plotly.

def plotDensity(data, col = '', target = '', title = '', xaxis = '', group = False,
                yaxis = 'Densidade', color = ['#8783D1', '#FADF63', '#3AAED8'], 
                template = 'plotly_white'):
    
    # Realizando as pré-configurações necessárias, para a plotagem do gráfico interativo.

    configure_plotly_browser_state()

    # Criando um gráfico de Densidade para o conjunto de dados.

    if group == False:

        # Definindo os dados, a cor, e os labels que serão utilizados para criar o gráfico de Densidade.

        fig = ff.create_distplot (
            [data], 
            group_labels = [xaxis], 
            colors       = [color[2]], 
            show_hist    = False, 
            show_rug     = False
        )

    # Criando um gráfico de Densidade para o conjunto de dados agrupado por categorias.

    else:

        # Captura os registros pertencentes a cada categoria, da variável categórica.

        g = [data[data[target] == cat][col] for cat in data[target].cat.categories]
        
        # Definindo os dados, a cor, e os labels que serão utilizados para criar cada um dos gráficos de Densidade.

        fig = ff.create_distplot (
            g, 
            group_labels = [n.capitalize() for n in data[target].cat.categories], 
            colors       = color, 
            show_hist    = False, 
            show_rug     = False
        )

    # Defindo as configurações de layout.

    fig.update_layout (
        title_text = title, 
        yaxis      = {"title_text": yaxis}, 
        xaxis      = {"title_text": xaxis}, 
        template   = template
    )

    # Plotando o Figure com o pyplot.

    fig.show()

4.1.3 Gráficos de Comparação

Os gráficos de comparação são usados para comparar um ou mais conjuntos de dados. Eles podem comparar itens ou mostrar diferenças ao longo do tempo.

In [15]:
# Definindo uma função, para criar gráficos de Barra interativos com o plotly.

def plotBar(data, col = '', target = '', title = '', yaxis = '', xaxis = '', kind = 'normal', 
            color = ['#8783D1', '#FADF63', '#FF9F43', '#EE6352', '#FC7A1E'], opacity = 0.65, 
            template = 'plotly_white', orientation = 'v'):
    
    # Realizando as pré-configurações necessárias para a plotagem do gráfico interativo.

    configure_plotly_browser_state()

    # Criando gráficos na vertical.

    if orientation == 'v':

        # Plotando gráfico de barras simples.

        if kind == 'normal':
            
            # Definindo os dados, a cor, orientação e a transparência que serão utilizados para criar as barras.

            dataTrace = go.Bar (
                x           = data.index, 
                y           = data.values, 
                marker      = {'color': color[2], "opacity": opacity}, 
                orientation = orientation
            ) 
        
        # Plotando gráfico de barras agrupado por uma variável categórica.

        elif kind == 'groups':
            
            # Captura os registros pertencentes a cada categoria, da variável categórica.

            g = [data[data[target] == cat] for cat in data[target].cat.categories]

            # Definindo os dados, a cor, orientação e a transparência que serão utilizados para criar as barras.

            dataTrace = [
                go.Bar (
                    x           = g[cat][col], 
                    y           = g[cat]['count'], 
                    name        = data[target].cat.categories[cat].capitalize(),
                    marker      = {'color': color[cat], "opacity": opacity}, 
                    orientation = orientation) 
                for cat in range(0,len(g))
            ]
    
    # Criando gráficos na horizontal.

    else:

        # Plotando gráfico de barras simples.
        
        if kind == 'normal':
            
            # Definindo os dados, a cor, orientação e a transparência que serão utilizados para criar as barras.

            dataTrace = go.Bar(
                x           = data.values, 
                y           = data.index, 
                marker      = {'color': color[3], "opacity": opacity}, 
                orientation = orientation
            ) 
        
        # Plotando gráfico de barras agrupado por uma variável categórica.

        elif kind == 'groups': 

            # Captura os registros pertencentes a cada categoria, da variável categórica.

            g = [data[data[target] == cat] for cat in data[target].cat.categories]

            # Definindo os dados, a cor, orientação e a transparência que serão utilizados para criar as barras.

            dataTrace = [
                go.Bar(
                    x           = g[cat]['count'], 
                    y           = g[cat][col], 
                    name        = data[target].cat.categories[cat].capitalize(), 
                    marker      = {'color': color[cat], "opacity": opacity}, 
                    orientation = orientation) 
                for cat in range(0,len(g))
            ]

    # Defindo as configurações de layout.

    layout = go.Layout(
        title    = title,
        yaxis    = {'title': yaxis},
        xaxis    = {'title': xaxis},
        template = template
    )

    # Criando uma Figure, com os dados e o layout defindos.

    fig = go.Figure(data = dataTrace, layout = layout)

    # Definindo que as barras devem ser dispostas uma ao lado da outra caso estejam agrupadas por categoria.
    # Para criar Stacked Bars, utilize: 'stack'.

    fig.update_layout(barmode = 'group')  

    # Plotando o Figure com o pyplot.

    fig.show()

4.1.4 Gráficos de Composição

Os gráficos de composição são usados para exibir partes de um todo e mudar ao longo do tempo.

In [16]:
# Definindo uma função, para realizar a plotagem de gráficos de pizza.

def plotPie(data, title = ''):

    # Realizando as pré-configurações necessárias, para a plotagem do gráfico interativo.

    configure_plotly_browser_state()

    # Defindo as configurações de layout.

    layout = go.Layout (
        title = title
    )

    # Criando uma Figure, com os dados e o layout defindos.

    fig = go.Figure (
        data   = [
            go.Pie(
                labels = [i[0].upper() + i[1:] for i in dataCounts.index], 
                values = dataCounts.values, 
                hole = .1)
        ],
        layout = layout
    )

    # Adicionando uma borda branca em cada uma das fatias da pizza.

    fig.update_traces (
        marker = dict (
            line = dict (
                color = '#FFFFFF', 
                width = 1
            )
        )
    )

    # Plotando a Figure com o pyplot.

    fig.show()

4.1.5 Gráficos de Relacionamento

Os gráficos de relacionamento são usados para mostrar uma conexão ou correlação entre duas ou mais variáveis.

In [17]:
# Definindo uma função, para realizar a plotagem de gráficos de correlação.

def plotCorr(corr, figsize = (18, 18), cmap = 'Blues', title = 'Gráfico de Correlação entre as variáveis do Data Frame'):
    
    # Criando uma máscara, com as mesmas dimensões da matriz de correlação.

    mask = np.zeros_like(corr)

    # Selecionando a matriz triangular inferior da máscara.

    mask[np.triu_indices_from(mask)] = True

    # Definindo as dimensões do gráfico a ser plotado.

    _, ax = plt.subplots(figsize = figsize)

    # Criando o gráfico Heatmap.

    ax = sns.heatmap (
        data       = corr, 
        mask       = mask, 
        vmax       = .3, 
        linewidths = .5,
        square     = True, 
        cmap       = cmap,
        annot      = True
    )

    # Definindo o título do gráfico.

    ax = ax.set_title(title)

4.1.6 Funções para calcular estatísticas

Criaremos uma função, para padronizar as estatísticas que calcularemos, em cada uma das variáveis a serem estudadas.

In [18]:
# Definindo uma função, para gerar um dataframe, com as estatísticas de uma variável do dataset.

def varStats(col, data, target = ''):

    if target == '':

        # Criando um dataframe, com as estatísticas da variável especificada.
        
        stats = pd.DataFrame({
            'min'   : data[col].min(),
            'Q1'    : data[col].quantile(.25),
            'Median': data[col].median(),
            'Mean'  : data[col].mean(),
            'Q3'    : data[col].quantile(.75),
            'SD'    : data[col].std(),
            'Sk'    : skew(data[col]),
            'Ck'    : kurtosis(data[col])
        }, index = [col])

    else:

        # Criando um dataframe, com as estatísticas da variável especificada, agrupada pela variável target.

        stats = pd.concat([
            data[[col, target]].groupby(target).min(),
            data[[col, target]].groupby(target).quantile(.25),
            data[[col, target]].groupby(target).median(),
            data[[col, target]].groupby(target).mean(),
            data[[col, target]].groupby(target).quantile(.75),
            data[[col, target]].groupby(target).std(),
            data[[col, target]].groupby(target).skew(),
            data[[col, target]].groupby(target).apply(lambda group: kurtosis(group)[0])

        ], axis = 1)

        # Renomeando as colunas do DataFrame.

        stats.columns = ['min', 'Q1', 'Median', 'Mean', 'Q3', 'SD', 'Sk', 'Ck']

    # Retornando os resultados obtidos.
    
    return stats

O coeficente de Assimetria (Skewness), indica como os dados estão distribuídos, e para interpretar seu resultado podemos olhar a tabela a seguir:

Índice de Assimetria Descrição
SK ≈ 0 Os dados são simétricos. Tanto a cauda do lado direito, quanto a do lado esquerdo da função densidade de probabilidade, são iguais;
SK < 0 A assimetria é negativa. A cauda do lado esquerdo da função densidade de probabilidade, é maior que a do lado direito e;
SK > 0 A assimetria é positiva. A cauda do lado direito da função densidade de probabilidade, é maior que a do lado esquerdo.

O coeficiente de Curtose (Kurtosis), é uma medida que caracteriza o achatamento da curva da função de distribuição, e para interpretar seu resultado, podemos olhar a tabela a seguir:

Índice de Curtose Descrição
CK ≈ 0 A distribuição é normal, e é chamada de Curtose Mesocúrtica;
CK < 0 A Cauda é mais leve que a normal. Para um coeficiente de Curtose negativo, tem-se uma Curtose Platicúrtica e;
CK > 0 A Cauda é mais pesada que a normal. Para um coeficiente de Curtose positivo, tem-se uma Curtose Leptocúrtica.

4.2 Explorando a distribuição de cada variável individualmente

4.2.1 Variável num_gestacoes

In [19]:
# Definindo o nome da variável a ser analisada.

col = 'num_gestacoes'

# Definindo a descrição da variável nos gráficos.

label = 'Número de Gestações'

# Contabilizando a frequência absoluta de cada categoria presente na variável especificada.

dataCounts = data[col].value_counts()

# Plotando um gráfico de barras para as variáveis especificadas.

plotBar (
    data        = dataCounts,
    title       = 'Frequência absoluta das categorias da Feature ' + col, 
    yaxis       = label, 
    xaxis       = 'Frequência Absoluta',
    orientation = 'h'
)

O número de gestações mais frequentes é 1.

In [20]:
# Criando um gráfico de Densidade para a variável especificada.

plotDensity (
    data  = data[col], 
    title = 'Gráfico de Densidade para a variável ' + col, 
    xaxis = label
)
In [21]:
# Plotando um gráfico de boxplot para as variável especificada.

plotBoxplot (
    data  = data[[col]],
    title = 'Boxplot para a variável ' + col,
    xaxis = 'Variável',
    name  = label
)

Números de gestações maiores do que 13, são outliers dentro do conjunto de dados.

In [22]:
# Calculando algumas estatísticas para a variável especificada.

varStats(col, data = data)
Out[22]:
min Q1 Median Mean Q3 SD Sk Ck
num_gestacoes 0 1.0 3.0 3.845052 6.0 3.369578 0.899912 0.150383

Destacamos que:

  • A média e a mediana do número de gestações apresentam valores diferentes;
  • O coeficiente de assimetria (Sk) confirma que os dados apresentam uma assimetria à direita;
  • O coeficiente de curtose (Ck) evidência que a calda é mais pesada que a normal, ou seja, temos uma curtose leptocúrtica.

4.2.2 Variável glicose

In [23]:
# Definindo o nome da variável a ser analisada.

col = 'glicose'

# Definindo a descrição da variável nos gráficos.

label = 'Glicose'

# Contabilizando a frequência absoluta de cada categoria presente na variável especificada.

dataCounts = data[col].value_counts()

# Plotando um gráfico de histograma para a variável especificada.

plotHist (
    data = data[col],
    title = 'Histograma para a variável ' + col,
    xaxis = label,
    yaxis = 'Frequência Absoluta'
)

A partir do histograma, podemos observar que o valor 0 para a glicose é, no mínimo, suspeito.

A hipoglicemia ocorre quando a glicemia está abaixo de 55 mg/dL. Suas causas mais comuns são os medicamentos tomados para controlar a diabetes. Causas muito menos comuns da hipoglicemia incluem outros medicamentos, doença crítica ou insuficiência de órgão, uma reação a carboidratos (em pessoas suscetíveis), um tumor produtor de insulina no pâncreas e alguns tipos de cirurgia bariátrica (para perda de peso).

O diagnóstico de um diabético com hipoglicemia é baseado em encontrar níveis baixos de glicose no sangue quando a pessoa apresentar os sintomas.

Mesmo que haja a possibilidade dos valores da glicose serem iguais a zero, a probabilidade de sua ocorrência parece ser mínima. E por isso, iremos tratá-los como erros.

Para saber mais, consulte este link.

In [24]:
# Criando um gráfico de Densidade para a variável especificada.

plotDensity (
    data  = data[col], 
    title = 'Gráfico de Densidade para a variável ' + col, 
    xaxis = label
)
In [25]:
# Plotando um gráfico de boxplot para as variáveis especificadas.

plotBoxplot (
    data  = data[[col]],
    title = 'Boxplot para a variável ' + col,
    xaxis = 'Variável',
    name  = label
)

Detectamos que a glicose, com valor 0, é um outlier dentro do conjunto de dados.

In [26]:
# Calculando algumas estatísticas para a variável especificada.

varStats(col, data = data)
Out[26]:
min Q1 Median Mean Q3 SD Sk Ck
glicose 0 99.0 117.0 120.894531 140.25 31.972618 0.173414 0.628813

Destacamos que:

  • A média e a mediana do valor da glicose apresentam valores próximos;
  • O coeficiente de assimetria (Sk) confirma que os dados apresentam uma assimetria à direita;
  • O coeficiente de curtose (Ck) evidência que a calda é mais pesada que a normal, ou seja, temos uma curtose leptocúrtica.

4.2.3 Variável pressao_sanguinea

In [27]:
# Definindo o nome da variável a ser analisada.

col = 'pressao_sanguinea'

# Definindo a descrição da variável nos gráficos.

label = 'Pressão Sanguínea'

# Contabilizando a frequência absoluta de cada categoria presente na variável especificada.

dataCounts = data[col].value_counts()

# Plotando um gráfico de histograma para a variável especificada.

plotHist (
    data = data[col],
    title = 'Histograma para a variável ' + col,
    xaxis = label,
    yaxis = 'Frequência Absoluta'
)

Para que a pressão sanguínea seja 0 mmHg, o coração do indivíduo: deveria parar de bater ou um erro de leitura (como o que é causado pelo fenômeno de Osler) deveria acontecer.

Em pessoas idosas, o endurecimento das artérias costuma acontecer, e ao se aferir a pressão sanguínea, escuta-se os batimentos cardíacos até o final. Isto dá a impressão de que o último som foi em 0 mmHg. Isto é muito comum e é chamdo de fenômeno de Osler.

Iremos considerar a pressão sanguínea de 0 mmHg, como erros de leitura.

Para saber mais, consulte este link.

In [28]:
# Criando um gráfico de Densidade para a variável especificada.

plotDensity (
    data  = data[col], 
    title = 'Gráfico de Densidade para a variável ' + col, 
    xaxis = label
)
In [29]:
# Plotando um gráfico de boxplot para a variável especificada.

plotBoxplot (
    data  = data[[col]],
    title = 'Boxplot para a variável ' + col,
    xaxis = 'Variável',
    name  = label
)

O boxplot nos indica que, há registros da pressão sanguínea discrepantes dentro do conjunto de dados.

In [30]:
# Calculando algumas estatísticas para a variável especificada.

varStats(col, data = data)
Out[30]:
min Q1 Median Mean Q3 SD Sk Ck
pressao_sanguinea 0 62.0 72.0 69.105469 80.0 19.355807 -1.840005 5.138691

Destacamos que:

  • A média e a mediana da pressão sanguínea apresentam valores próximos;
  • O coeficiente de assimetria (Sk) confirma que os dados apresentam uma assimetria à esquerda;
  • O coeficiente de curtose (Ck) evidência que a calda é mais pesada que a normal, ou seja, temos uma curtose leptocúrtica.

4.2.4 Variável grossura_pele

In [31]:
# Definindo o nome da variável a ser analisada.

col = 'grossura_pele'

# Definindo a descrição da variável nos gráficos.

label = 'Grossura da Pele'

# Contabilizando a frequência absoluta de cada categoria presente na variável especificada.

dataCounts = data[col].value_counts()

# Plotando um gráfico de histograma para a variável especificada.

plotHist (
    data = data[col],
    title = 'Histograma para a variável ' + col,
    xaxis = label,
    yaxis = 'Frequência Absoluta'
)

De cada 3 portadores de diabetes, um terá problemas na pele decorrentes da doença, mesmo que ela esteja tratada. Isso ocorre por vários motivos, mas os principais são:

Alteração das proteínas da pele pela glicação: a glicação é uma reação da glicose com proteínas presentes na derme, parede dos vasos sanguíneos e epiderme. Isso provoca alterações da elasticidade e espessura da pele, deixando-a mais frágil e com maior dificuldade de cicatrização; em pacientes que tratam a diabetes de maneira insuficiente ou irregular, estes problemas são ainda piores.

Podemos concluir, que muito provavelmente, as leituras em que a grossura da pele é igual a 0 mm são erros.

Para saber mais, consulte este link.

In [32]:
# Criando um gráfico de Densidade para a variável especificada.

plotDensity (
    data  = data[col], 
    title = 'Gráfico de Densidade para a variável ' + col, 
    xaxis = label
)
In [33]:
# Plotando um gráfico de boxplot para as variáveis especificadas.

plotBoxplot (
    data  = data[[col]],
    title = 'Boxplot para a variável ' + col,
    xaxis = 'Variável',
    name  = label
)

O boxplot nos indica que, há registros da grossura da pele discrepantes dentro do conjunto de dados.

In [34]:
# Calculando algumas estatísticas para a variável especificada.

varStats(col, data = data)
Out[34]:
min Q1 Median Mean Q3 SD Sk Ck
grossura_pele 0 0.0 23.0 20.536458 32.0 15.952218 0.109159 -0.524494

Destacamos que:

  • A média e a mediana da grossura da pele apresentam valores próximos;
  • O coeficiente de assimetria (Sk) confirma que os dados apresentam uma assimetria à direita;
  • O coeficiente de curtose (Ck) evidência que a calda é mais leve que a normal, ou seja, temos uma curtose Platicúrtica.

4.2.5 Variável insulina

In [35]:
# Definindo o nome da variável a ser analisada.

col = 'insulina'

# Definindo a descrição da variável nos gráficos.

label = 'Insulina'

# Contabilizando a frequência absoluta de cada categoria presente na variável especificada.

dataCounts = data[col].value_counts()

# Plotando um gráfico de histograma para a variável especificada.

plotHist (
    data = data[col],
    title = 'Histograma para a variável ' + col,
    xaxis = label,
    yaxis = 'Frequência Absoluta'
)

A insulina é um hormônio produzido pelo pâncreas, e tem como função metabolizar a glicose (açúcar no sangue) para produção de energia. Ela atua como uma "chave", abrindo as "fechaduras" das células do corpo, para que a glicose entre e seja usada para gerar energia. Ou seja, o hormônio ajuda a glicose a entrar nas células do corpo.

Quando há alguma disfunção na produção de insulina, pouca ou nenhuma produção de insulina, a pessoa é diagnosticada com Diabetes Mellitus. Para o controle da glicose na corrente sanguínea, muitas vezes é necessário realizar a reposição exógena da insulina com aplicações diárias do hormônio.

Os valores dos registros em que a insulina é 0 µU/ml serão tratados como erros.

In [36]:
# Criando um gráfico de Densidade para a variável especificada.

plotDensity (
    data  = data[col], 
    title = 'Gráfico de Densidade para a variável ' + col, 
    xaxis = label
)
In [37]:
# Plotando um gráfico de boxplot para a variável especificada.

plotBoxplot (
    data  = data[[col]],
    title = 'Boxplot para a variável ' + col,
    xaxis = 'Variável',
    name  = label
)

Os valores de insulina que são maiores que 318 µU/ml são outliers.

In [38]:
# Calculando algumas estatísticas para a variável especificada.

varStats(col, data = data)
Out[38]:
min Q1 Median Mean Q3 SD Sk Ck
insulina 0 0.0 30.5 79.799479 127.25 115.244002 2.26781 7.159575

Destacamos que:

  • A média e a mediana do valor da insulina apresentam valores diferentes;
  • O coeficiente de assimetria (Sk) confirma que os dados apresentam uma assimetria à direita;
  • O coeficiente de curtose (Ck) evidência que a calda é mais pesada que a normal, ou seja, temos uma curtose Leptocúrtica.

4.2.6 Variável bmi

In [39]:
# Definindo o nome da variável a ser analisada.

col = 'bmi'

# Definindo a descrição da variável nos gráficos.

label = 'BMI'

# Contabilizando a frequência absoluta de cada categoria presente na variável especificada.

dataCounts = data[col].value_counts()

# Plotando um gráfico de histograma para a variável especificada.

plotHist (
    data = data[col],
    title = 'Histograma para a variável ' + col,
    xaxis = label,
    yaxis = 'Frequência Absoluta'
)

A medicina demonstrou que o controle de peso tem um papel importante no tratamento e desenvolvimento de uma nova vida com diabetes. Em particular, a prevenção da obesidade e do sobrepeso também reduz o risco de outras doenças crônicas perigosas, como a pressão arterial alta.

O índice de massa corporal (IMC) ou Body mass index (BMI) é um valor especial que mostra se o peso de uma pessoa está em um nível adequado ou não. Este valor se calcula em função da relação entre o peso e a altura, de acordo com a fórmula:

$IMC (kg / m^2) = Peso (kg) / [Altura (m)]^2$

De modo geral, em adultos, o IMC normal fica entre 18,5 a 23 $kg / m^2$. Quanto mais alto seja o número, mais peso sobra, e mais obeso é e deve começar a emagrecer de forma razoável.

A partir de uma análise da fórmula utilizada para calcular o IMC, podemos concluir que os registros em que seu valor é 0 são erros.

Para saber mais, consulte este link.

In [40]:
# Criando um gráfico de Densidade para a variável especificada.

plotDensity (
    data  = data[col], 
    title = 'Gráfico de Densidade para a variável ' + col, 
    xaxis = label
)
In [41]:
# Plotando um gráfico de boxplot para a variável especificada.

plotBoxplot (
    data  = data[[col]],
    title = 'Boxplot para a variável ' + col,
    xaxis = 'Variável',
    name  = label
)

O boxplot nos indica que, há registros da BMI discrepantes dentro do conjunto de dados.

In [42]:
# Calculando algumas estatísticas para a variável especificada.

varStats(col, data = data)
Out[42]:
min Q1 Median Mean Q3 SD Sk Ck
bmi 0.0 27.3 32.0 31.992578 36.6 7.88416 -0.428143 3.261257

Destacamos que:

  • A média e a mediana do valor da BMI apresentam valores próximos;
  • O coeficiente de assimetria (Sk) confirma que os dados apresentam uma assimetria à esquerda;
  • O coeficiente de curtose (Ck) evidência que a calda é mais pesada que a normal, ou seja, temos uma curtose Leptocúrtica.

4.2.7 Variável indice_historico

In [43]:
# Definindo o nome da variável a ser analisada.

col = 'indice_historico'

# Definindo a descrição da variável nos gráficos.

label = 'Índice Histórico'

# Contabilizando a frequência absoluta de cada categoria presente na variável especificada.

dataCounts = data[col].value_counts()

# Plotando um gráfico de histograma para a variável especificada.

plotHist (
    data = data[col],
    title = 'Histograma para a variável ' + col,
    xaxis = label,
    yaxis = 'Frequência Absoluta'
)

O índice de histórico de diabetes (Pedigree Function) mais frequente está entre 0.25 e 0.299.

In [44]:
# Criando um gráfico de Densidade para a variável especificada.

plotDensity (
    data  = data[col], 
    title = 'Gráfico de Densidade para a variável ' + col, 
    xaxis = label
)
In [45]:
# Plotando um gráfico de boxplot para as variável especificada.

plotBoxplot (
    data  = data[[col]],
    title = 'Boxplot para a variável ' + col,
    xaxis = 'Variável',
    name  = label
)

Os índices de histórico de diabetes maiores do que 1.191 são outliers.

In [46]:
# Calculando algumas estatísticas para a variável especificada.

varStats(col, data = data)
Out[46]:
min Q1 Median Mean Q3 SD Sk Ck
indice_historico 0.078 0.24375 0.3725 0.471876 0.62625 0.331329 1.916159 5.550792

Destacamos que:

  • A média e a mediana do índice de histórico de diabetes apresentam valores diferentes;
  • O coeficiente de assimetria (Sk) confirma que os dados apresentam uma assimetria à direita;
  • O coeficiente de curtose (Ck) evidência que a calda é mais pesada que a normal, ou seja, temos uma curtose Leptocúrtica.

4.2.8 Variável idade

In [47]:
# Definindo o nome da variável a ser analisada.

col = 'idade'

# Definindo a descrição da variável nos gráficos.

label = 'Idade'

# Contabilizando a frequência absoluta de cada categoria presente na variável especificada.

dataCounts = data[col].value_counts()

# Plotando um gráfico de histograma para a variável especificada.

plotHist (
    data = data[col],
    title = 'Histograma para a variável ' + col,
    xaxis = label,
    yaxis = 'Frequência Absoluta'
)

A idade mais frequente das mulheres está entre 22 e 23 anos dentro do conjunto de dados.

In [48]:
# Criando um gráfico de Densidade para a variável especificada.

plotDensity (
    data  = data[col], 
    title = 'Gráfico de Densidade para a variável ' + col, 
    xaxis = label
)
In [49]:
# Plotando um gráfico de boxplot para as variável especificada.

plotBoxplot (
    data  = data[[col]],
    title = 'Boxplot para a variável ' + col,
    xaxis = 'Variável',
    name  = label
)

Idades maiores do que 66 anos são outliers.

In [50]:
# Calculando algumas estatísticas para a variável especificada.

varStats(col, data = data)
Out[50]:
min Q1 Median Mean Q3 SD Sk Ck
idade 21 24.0 29.0 33.240885 41.0 11.760232 1.127389 0.631177

Destacamos que:

  • A média e a mediana da idade apresentam valores próximos;
  • O coeficiente de assimetria (Sk) confirma que os dados apresentam uma assimetria à direita;
  • O coeficiente de curtose (Ck) evidência que a calda é mais pesada que a normal, ou seja, temos uma curtose Leptocúrtica.

4.2.9 Variável diabetes

In [51]:
# Definindo o nome da variável a ser analisada.

col = 'diabetes'

# Definindo a descrição da variável nos gráficos.

label = 'Diabetes'

# Contabilizando a frequência absoluta de cada categoria presente na variável especificada.

dataCounts = data[col].value_counts()

# Plotando um gráfico de barras para as variável especificada.

plotBar (
    data  = dataCounts,
    title = 'Frequência absoluta das categorias da Feature ' + col, 
    yaxis = 'Frequência Absoluta', 
    xaxis = label
)
In [52]:
# Plotando um gráfico de pizza para a variável especificada.

plotPie (
    data  = dataCounts, 
    title = 'Frequência relativa das categorias da feature ' + col
)

A proporção de mulheres com diabetes dentro do conjunto de dados é menor. O conjunto de dados está desbalanceado.

4.3 Explorando a distribuição de cada Feature a partir da variável Target

4.3.1 Variável num_gestacoes

In [53]:
# Definindo o nome da variável a ser analisada.

col = 'num_gestacoes'

# Definindo o nome da variável Target.

target = 'diabetes'

# Definindo a descrição da variável nos gráficos.

label = 'Número de Gestações'

# Capturando variáveis especificadas do Dataset.

dt = data[[col, target]]

# Criando uma variável count para contabilizar as ocorrências de cada registro.

dt['count'] = 1

# Agrupando dados e contabilizando o número de ocorrências.

dt = dt.groupby(by = [target, col]).sum()

# Reorganizando DataFrame. 

dt = dt.reset_index()

# Plotando um gráfico de histograma para a variável especificada.

plotHist (
    data   = data[[col, target]],
    title  = 'Histograma para a variável ' + col,
    xaxis  = label,
    yaxis  = 'Frequência Absoluta',
    col    = col,
    target = target,
    groups = True
)

Parece que conforme o número de gestações aumenta, a proporção de mulheres diabéticas também aumenta.

In [54]:
# Criando um gráfico de Densidade para a variável especificada.

plotDensity (
    data   = data[[col, target]], 
    title  = 'Gráfico de Densidade para a variável ' + col, 
    xaxis  = label,
    col    = col,
    target = target,
    group  = True
)

A distribuição de densidade da mulheres que não tem diabetes, é mais uniforme do que aquelas que possuem a doença.

In [55]:
# Plotando um gráfico de boxplot para a variável especificada.

plotBoxplot (
    data   = data[[col, target]],
    title  = 'Boxplot para a variável ' + col,
    yaxis  = label,
    xaxis  = target.capitalize(),
    col    = col,
    target = target,
    kind   = 'groups'
)

O número mediano de gestações das mulheres que apresentam diabetes é maior.

In [56]:
# Calculando algumas estatísticas para a variável especificada.

varStats(col = col, data = data, target = target)
Out[56]:
min Q1 Median Mean Q3 SD Sk Ck
diabetes
No 0 1.00 2 3.298000 5.0 3.017185 1.114105 0.668438
Yes 0 1.75 4 4.865672 8.0 3.741239 0.503749 -0.455751

Destacamos que:

  • A média e a mediana do número de gestações, apresenta valores diferentes;
  • O coeficiente de assimetria (Sk), evidência que o grupo de mulheres que não tem diabetes, tem uma assimetria à direita maior;
  • O coeficiente de curtose (Ck), evidência que o grupo de mulheres que não tem diabetes, apresenta uma calda mais pesada que a normal.

4.3.2 Variável glicose

In [57]:
# Definindo o nome da variável a ser analisada.

col = 'glicose'

# Definindo o nome da variável Target.

target = 'diabetes'

# Definindo a descrição da variável nos gráficos.

label = 'Glicose'

# Capturando variáveis especificadas do Dataset.

dt = data[[col, target]]

# Criando uma variável count para contabilizar as ocorrências de cada registro.

dt['count'] = 1

# Agrupando dados e contabilizando o número de ocorrências.

dt = dt.groupby(by = [target, col]).sum()

# Reorganizando DataFrame. 

dt = dt.reset_index()

# Plotando um gráfico de histograma para a variável especificada.

plotHist (
    data   = data[[col, target]],
    title  = 'Histograma para a variável ' + col,
    xaxis  = label,
    yaxis  = 'Frequência Absoluta',
    col    = col,
    target = target,
    groups = True
)

A distribuição dos valores da glicose, para as mulheres que não tem diabetes, é mais simétrica.

In [58]:
# Criando um gráfico de Densidade para a variável especificada.

plotDensity (
    data   = data[[col, target]], 
    title  = 'Gráfico de Densidade para a variável ' + col, 
    xaxis  = label,
    col    = col,
    target = target,
    group  = True
)

A distribuição de densidade da glicose das mulheres que não tem diabetes, é mais simétrica.

In [59]:
# Plotando um gráfico de boxplot para as variáveis especificadas.

plotBoxplot (
    data   = data[[col, target]],
    title  = 'Boxplot para a variável ' + col,
    yaxis  = label,
    xaxis  = target.capitalize(),
    col    = col,
    target = target,
    kind   = 'groups'
)

O valor mediano da glicose das mulheres que tem diabetes é maior. E segundo a American Diabetes Association (Organização Mundial da Saúde e Sociedade Brasileira de diabetes), um dos critérios utilizados para identificar se um indivíduo possuí diabetes, é possuir uma glicose maior ou igual 126 mg/dL.

Para saber mais, consulte este link.

In [60]:
# Calculando algumas estatísticas para a variável especificada.

varStats(col = col, data = data, target = target)
Out[60]:
min Q1 Median Mean Q3 SD Sk Ck
diabetes
No 0 93.0 107 109.980000 125.0 26.141200 0.173111 1.869593
Yes 0 119.0 140 141.257463 167.0 31.939622 -0.495557 1.383079

Destacamos que:

  • A média e a mediana do valor da glicose, apresenta valores diferentes;
  • O coeficiente de assimetria (Sk), evidência que o grupo de mulheres que possui diabetes, tem uma assimetria à esquerda maior;
  • O coeficiente de curtose (Ck), evidência que o grupo de mulheres que não tem diabetes, apresenta uma calda mais pesada que a normal.

4.3.3 Variável pressao_sanguinea

In [61]:
# Definindo o nome da variável a ser analisada.

col = 'pressao_sanguinea'

# Definindo o nome da variável Target.

target = 'diabetes'

# Definindo a descrição da variável nos gráficos.

label = 'Pressão Sanguínea'

# Capturando variáveis especificadas do Dataset.

dt = data[[col, target]]

# Criando uma variável count para contabilizar as ocorrências de cada registro.

dt['count'] = 1

# Agrupando dados e contabilizando o número de ocorrências.

dt = dt.groupby(by = [target, col]).sum()

# Reorganizando DataFrame. 

dt = dt.reset_index()

# Plotando um gráfico de histograma para a variável especificada.

plotHist (
    data   = data[[col, target]],
    title  = 'Histograma para a variável ' + col,
    xaxis  = label,
    yaxis  = 'Frequência Absoluta',
    col    = col,
    target = target,
    groups = True
)

A pressão sanguínea das mulheres com diabetes aparenta ser maior.

A diabetes colabora para a pressão alta se instaurar. A resistência à insulina, condição típica do diabético tipo 2, é uma falha no organismo que dificulta o acesso das células à glicose circulante. Desta forma, uma grande quantidade de açúcar fica sobrando no sangue. Esse fenômeno contribui para as artérias se enrijecerem, o que está por trás do aumento da pressão.

Para saber mais, consulte este link.

In [62]:
# Criando um gráfico de Densidade para a variável especificada.

plotDensity (
    data   = data[[col, target]], 
    title  = 'Gráfico de Densidade para a variável ' + col, 
    xaxis  = label,
    col    = col,
    target = target,
    group  = True
)

A distribuição de densidade da pressão sanguínea, tem um valor mediano maior para as mulheres que possuem diabetes.

In [63]:
# Plotando um gráfico de boxplot para as variáveis especificadas.

plotBoxplot (
    data   = data[[col, target]],
    title  = 'Boxplot para a variável ' + col,
    yaxis  = label,
    xaxis  = target.capitalize(),
    col    = col,
    target = target,
    kind   = 'groups'
)

Há outliers nos dois grupos de mulheres.

In [64]:
# Calculando algumas estatísticas para a variável especificada.

varStats(col = col, data = data, target = target)
Out[64]:
min Q1 Median Mean Q3 SD Sk Ck
diabetes
No 0 62.0 70 68.184000 78.0 18.063075 -1.809825 5.618290
Yes 0 66.0 74 70.824627 82.0 21.491812 -1.943633 4.590026

Destacamos que:

  • A média e a mediana da pressão sanguínea, apresenta valores diferentes;
  • O coeficiente de assimetria (Sk), evidência que o grupo de mulheres que possui diabetes, tem uma assimetria à esquerda maior;
  • O coeficiente de curtose (Ck), evidência que o grupo de mulheres que não tem diabetes, apresenta uma calda mais pesada que a normal.

4.3.4 Variável grossura_pele

In [65]:
# Definindo o nome da variável a ser analisada.

col = 'grossura_pele'

# Definindo o nome da variável Target.

target = 'diabetes'

# Definindo a descrição da variável nos gráficos.

label = 'Grossura da Pele'

# Capturando variáveis especificadas do Dataset.

dt = data[[col, target]]

# Criando uma variável count para contabilizar as ocorrências de cada registro.

dt['count'] = 1

# Agrupando dados e contabilizando o número de ocorrências.

dt = dt.groupby(by = [target, col]).sum()

# Reorganizando DataFrame. 

dt = dt.reset_index()

# Plotando um gráfico de histograma para a variável especificada.

plotHist (
    data   = data[[col, target]],
    title  = 'Histograma para a variável ' + col,
    xaxis  = label,
    yaxis  = 'Frequência Absoluta',
    col    = col,
    target = target,
    groups = True
)

A grossura da pele parece ser maior para o grupo de mulheres que possui diabetes.

In [66]:
# Criando um gráfico de Densidade para a variável especificada.

plotDensity (
    data   = data[[col, target]], 
    title  = 'Gráfico de Densidade para a variável ' + col, 
    xaxis  = label,
    col    = col,
    target = target,
    group  = True
)

A distribuição de densidade do grupo de mulheres que possui diabetes, possui um valor mediano maior.

In [67]:
# Plotando um gráfico de boxplot para a variável especificada.

plotBoxplot (
    data   = data[[col, target]],
    title  = 'Boxplot para a variável ' + col,
    yaxis  = label,
    xaxis  = target.capitalize(),
    col    = col,
    target = target,
    kind   = 'groups'
)

Há outliers, no grupo de mulheres que possui diabetes.

In [68]:
# Calculando algumas estatísticas para a variável especificada.

varStats(col = col, data = data, target = target)
Out[68]:
min Q1 Median Mean Q3 SD Sk Ck
diabetes
No 0 0.0 21 19.664000 31.0 14.889947 0.031155 -1.039829
Yes 0 0.0 27 22.164179 36.0 17.679711 0.115910 -0.227702

Destacamos que:

  • A média e a mediana da grossura da pele, apresenta valores diferentes;
  • O coeficiente de assimetria (Sk), evidência que o grupo de mulheres que possui diabetes, tem uma assimetria à direita maior;
  • O coeficiente de curtose (Ck), evidência que o grupo de mulheres que não tem diabetes, apresenta uma calda mais leve que a normal.

4.3.5 Variável insulina

In [69]:
# Definindo o nome da variável a ser analisada.

col = 'insulina'

# Definindo o nome da variável Target.

target = 'diabetes'

# Definindo a descrição da variável nos gráficos.

label = 'Insulina'

# Capturando variáveis especificadas do Dataset.

dt = data[[col, target]]

# Criando uma variável count para contabilizar as ocorrências de cada registro.

dt['count'] = 1

# Agrupando dados e contabilizando o número de ocorrências.

dt = dt.groupby(by = [target, col]).sum()

# Reorganizando DataFrame. 

dt = dt.reset_index()

# Plotando um gráfico de histograma para a variável especificada.

plotHist (
    data   = data[[col, target]],
    title  = 'Histograma para a variável ' + col,
    xaxis  = label,
    yaxis  = 'Frequência Absoluta',
    col    = col,
    target = target,
    groups = True
)

As mulheres com diabetes, aparentam ter taxas de insulina menores.

In [70]:
# Criando um gráfico de Densidade para a variável especificada.

plotDensity (
    data   = data[[col, target]], 
    title  = 'Gráfico de Densidade para a variável ' + col, 
    xaxis  = label,
    col    = col,
    target = target,
    group  = True
)
In [71]:
# Plotando um gráfico de boxplot para a variável especificada.

plotBoxplot (
    data   = data[[col, target]],
    title  = 'Boxplot para a variável ' + col,
    yaxis  = label,
    xaxis  = target.capitalize(),
    col    = col,
    target = target,
    kind   = 'groups'
)

Há outliers, nos dois conjuntos de dados.

In [72]:
# Calculando algumas estatísticas para a variável especificada.

varStats(col = col, data = data, target = target)
Out[72]:
min Q1 Median Mean Q3 SD Sk Ck
diabetes
No 0 0.0 39 68.792000 105.00 98.865289 2.498741 9.351499
Yes 0 0.0 0 100.335821 167.25 138.689125 1.843831 4.257259

Destacamos que:

  • A média e a mediana da insulina, apresenta valores diferentes;
  • O coeficiente de assimetria (Sk), evidência que o grupo de mulheres que não possui diabetes, tem uma assimetria à direita maior;
  • O coeficiente de curtose (Ck), evidência que o grupo de mulheres que não tem diabetes, apresenta uma calda mais pesada que a normal.

4.3.6 Variável bmi

In [73]:
# Definindo o nome da variável a ser analisada.

col = 'bmi'

# Definindo o nome da variável Target.

target = 'diabetes'

# Definindo a descrição da variável nos gráficos.

label = 'BMI'

# Capturando variáveis especificadas do Dataset.

dt = data[[col, target]]

# Criando uma variável count para contabilizar as ocorrências de cada registro.

dt['count'] = 1

# Agrupando dados e contabilizando o número de ocorrências.

dt = dt.groupby(by = [target, col]).sum()

# Reorganizando DataFrame. 

dt = dt.reset_index()

# Plotando um gráfico de histograma para a variável especificada.

plotHist (
    data   = data[[col, target]],
    title  = 'Histograma para a variável ' + col,
    xaxis  = label,
    yaxis  = 'Frequência Absoluta',
    col    = col,
    target = target,
    groups = True
)

O BMI das mulheres que possuem diabetes, aparenta ter uma distribuição mais normal.

In [74]:
# Criando um gráfico de Densidade para a variável especificada.

plotDensity (
    data   = data[[col, target]], 
    title  = 'Gráfico de Densidade para a variável ' + col, 
    xaxis  = label,
    col    = col,
    target = target,
    group  = True
)

A distribuição de densidade das mulheres que posssuem diabetes, aparenta ter um valor mediano maior.

In [75]:
# Plotando um gráfico de boxplot para a variável especificada.

plotBoxplot (
    data   = data[[col, target]],
    title  = 'Boxplot para a variável ' + col,
    yaxis  = label,
    xaxis  = target.capitalize(),
    col    = col,
    target = target,
    kind   = 'groups'
)

Há outliers, nos dois conjuntos de dados.

In [76]:
# Calculando algumas estatísticas para a variável especificada.

varStats(col = col, data = data, target = target)
Out[76]:
min Q1 Median Mean Q3 SD Sk Ck
diabetes
No 0.0 25.4 30.05 30.304200 35.300 7.689855 -0.665902 3.015812
Yes 0.0 30.8 34.25 35.142537 38.775 7.262967 0.000597 4.653103

Destacamos que:

  • A média e a mediana da BMI, apresenta valores diferentes;
  • O coeficiente de assimetria (Sk), evidência que o grupo de mulheres que não possui diabetes, tem uma assimetria à esquerda maior;
  • O coeficiente de curtose (Ck), evidência que o grupo de mulheres que não tem diabetes, apresenta uma calda mais pesada que a normal.

4.3.7 Variável indice_historico

In [77]:
# Definindo o nome da variável a ser analisada.

col = 'indice_historico'

# Definindo o nome da variável Target.

target = 'diabetes'

# Definindo a descrição da variável nos gráficos.

label = 'Índice Histórico'

# Capturando variáveis especificadas do Dataset.

dt = data[[col, target]]

# Criando uma variável count para contabilizar as ocorrências de cada registro.

dt['count'] = 1

# Agrupando dados e contabilizando o número de ocorrências.

dt = dt.groupby(by = [target, col]).sum()

# Reorganizando DataFrame. 

dt = dt.reset_index()

# Plotando um gráfico de histograma para a variável especificada.

plotHist (
    data   = data[[col, target]],
    title  = 'Histograma para a variável ' + col,
    xaxis  = label,
    yaxis  = 'Frequência Absoluta',
    col    = col,
    target = target,
    groups = True
)

O grupo de mulheres que não possui diabetes, apresenta índices com valores menores.

In [78]:
# Criando um gráfico de Densidade para a variável especificada.

plotDensity (
    data   = data[[col, target]], 
    title  = 'Gráfico de Densidade para a variável ' + col, 
    xaxis  = label,
    col    = col,
    target = target,
    group  = True
)
In [79]:
# Plotando um gráfico de boxplot para a variável especificada.

plotBoxplot (
    data   = data[[col, target]],
    title  = 'Boxplot para a variável ' + col,
    yaxis  = label,
    xaxis  = target.capitalize(),
    col    = col,
    target = target,
    kind   = 'groups'
)

O índice histórico das mulheres que possuem diabetes é maior.

In [80]:
# Calculando algumas estatísticas para a variável especificada.

varStats(col = col, data = data, target = target)
Out[80]:
min Q1 Median Mean Q3 SD Sk Ck
diabetes
No 0.078 0.22975 0.336 0.429734 0.56175 0.299085 2.006242 6.047920
Yes 0.088 0.26250 0.449 0.550500 0.72800 0.372354 1.722373 4.452163

Destacamos que:

  • A média e a mediana do índice histórico, apresenta valores diferentes;
  • O coeficiente de assimetria (Sk), evidência que o grupo de mulheres que não possui diabetes, tem uma assimetria à direita maior;
  • O coeficiente de curtose (Ck), evidência que o grupo de mulheres que não tem diabetes, apresenta uma calda mais pesada que a normal.

4.3.8 Variável idade

In [81]:
# Definindo o nome da variável a ser analisada.

col = 'idade'

# Definindo o nome da variável Target.

target = 'diabetes'

# Definindo a descrição da variável nos gráficos.

label = 'Idades'

# Capturando variáveis especificadas do Dataset.

dt = data[[col, target]]

# Criando uma variável count para contabilizar as ocorrências de cada registro.

dt['count'] = 1

# Agrupando dados e contabilizando o número de ocorrências.

dt = dt.groupby(by = [target, col]).sum()

# Reorganizando DataFrame. 

dt = dt.reset_index()

# Plotando um gráfico de histograma para a variável especificada.

plotHist (
    data   = data[[col, target]],
    title  = 'Histograma para a variável ' + col,
    xaxis  = label,
    yaxis  = 'Frequência Absoluta',
    col    = col,
    target = target,
    groups = True
)

As mulheres que não possuem diabetes, em geral, apresentam as menores idades.

In [82]:
# Criando um gráfico de Densidade para a variável especificada.

plotDensity (
    data   = data[[col, target]], 
    title  = 'Gráfico de Densidade para a variável ' + col, 
    xaxis  = label,
    col    = col,
    target = target,
    group  = True
)
In [83]:
# Plotando um gráfico de boxplot para a variável especificada.

plotBoxplot (
    data   = data[[col, target]],
    title  = 'Boxplot para a variável ' + col,
    yaxis  = label,
    xaxis  = target.capitalize(),
    col    = col,
    target = target,
    kind   = 'groups'
)

As mulheres que possuem diabetes, apresentam uma idade mediana maior.

In [84]:
# Calculando algumas estatísticas para a variável especificada.

varStats(col = col, data = data, target = target)
Out[84]:
min Q1 Median Mean Q3 SD Sk Ck
diabetes
No 21 23.0 27 31.190000 37.0 11.667655 1.571609 1.931873
Yes 21 28.0 36 37.067164 44.0 10.968254 0.581646 -0.363785

Destacamos que:

  • A média e a mediana das idades, apresenta valores diferentes;
  • O coeficiente de assimetria (Sk), evidência que o grupo de mulheres que não possui diabetes, tem uma assimetria à direita maior;
  • O coeficiente de curtose (Ck), evidência que o grupo de mulheres que não tem diabetes, apresenta uma calda mais pesada que a normal.

4.4 Analisando a correlação entre as variáveis

In [85]:
# Criando uma cópia do conjunto de dados.

dt = data.copy()

# Convertendo a variável target para o tipo inteiro.

dt['diabetes'] = dt['diabetes'].cat.codes

# Criando uma matriz de correlação.

corr = dt.corr()

# Selecionando o triângulo superior da matriz de correlação.

upper = corr.abs().where(np.triu(np.ones(corr.shape), k = 1).astype(np.bool))

# Plotando a matriz de correlação entre as variáveis do Dataset.

plotCorr(corr)

Todas as variáveis preditoras, apresentam uma correlação positiva e moderada com a variável target. As variáveis glicose, bmi e idade são as que possuem as correlações mais fortes.

5. Feature Selection

5.1 Criando funções auxiliares

In [86]:
# Definindo uma função para para aplicar as transformações MimMaxScaler, StandardScaler, 
# Yeo-Johnson e Normalize as features de um conjunto de dados de treino e de teste.

def dataTransform(train, test, transform = 'MM'):

    # Criando cópias dos DataFrames.

    trainFeatures = train.copy()
    testFeatures  = test.copy()
    
    # Criando um variável para identificar os dados de treino e de teste.

    trainFeatures['train'] = 1
    testFeatures['train']  = 0

    # Unindo dados de treino e de teste em um único conjunto de dados.

    features = pd.concat([trainFeatures, testFeatures])

    # Capturando a variável que identifica os dados de treino e de teste.

    train = features['train']

    # Eliminando a variável de identificação do Dataframe.

    features = features.drop('train', axis = 1)

    # Criando variável para armazenar o conjunto de dados transformado.

    featuresTransformed = None

    # Aplicando a transformação selecionada.

    if transform == 'MM':
        
        # Criando um objeto da classe MinMaxScaler().

        scaler = MinMaxScaler()

        # Aplicando a escala nas Features e capturando o resultado obtido.

        featuresTransformed = scaler.fit_transform(features)

        # Criando um DataFrame com os resultados obtidos.

        featuresTransformed = pd.DataFrame(data = featuresTransformed, columns = features.columns)
    
    elif transform == 'SS':

        # Criando um objeto da classe StandardScaler().

        scaler = StandardScaler()

        # Aplicando a escala nas Features e capturando o resultado obtido.

        featuresTransformed = scaler.fit_transform(features)

        # Criando um DataFrame com os resultados obtidos.

        featuresTransformed = pd.DataFrame(data = featuresTransformed, columns = features.columns)
    
    elif transform == 'ND':

        # Criando um objeto da classe StandardScaler().

        scaler = StandardScaler()

        # Aplicando a escala nas Features e capturando o resultado obtido.

        featuresTransformed = scaler.fit_transform(features)

        # Criando um DataFrame com os resultados obtidos.

        featuresTransformed = pd.DataFrame(data = featuresTransformed, columns = features.columns)

        # Criando um objeto da classe PowerTransformer().

        scaler = PowerTransformer(method = 'yeo-johnson', standardize = False)

        # Aplicando a escala nas Features e capturando o resultado obtido.

        featuresTransformed = scaler.fit_transform(featuresTransformed)

        # Criando um DataFrame com os resultados obtidos.

        featuresTransformed = pd.DataFrame(data = featuresTransformed, columns = features.columns)
    
    elif transform == 'N':

        # Normalizando cada feature para uma unidade uniforme (vetor unitário).

        featuresTransformed = normalize(features, axis = 0)

        # Criando um DataFrame com os resultados obtidos.

        featuresTransformed = pd.DataFrame(data = featuresTransformed, columns = features.columns)

    # Atribuindo variável identificadora ao DataFrame transformado.

    featuresTransformed['train'] = train.values

    # Separando dados de treino e de teste transformados.

    trFeatures  = featuresTransformed[featuresTransformed['train'] == 1].drop('train', axis = 1)
    tstFeatures = featuresTransformed[featuresTransformed['train'] == 0].drop('train', axis = 1)

    # Retornando dados de treino e teste transformados.

    return trFeatures, tstFeatures
In [87]:
# Definindo função para aplicar a técnica PCA a um conjunto de dados de treino e teste.

def pcaTransform(train, test, nComponents = 8):

    # Criando cópias dos DataFrames.

    trainFeatures = train.copy()
    testFeatures  = test.copy()
    
    # Criando um variável para identificar os dados de treino e de teste.

    trainFeatures['train'] = 1
    testFeatures['train']  = 0

    # Unindo dados de treino e de teste em um único conjunto de dados.

    features = pd.concat([trainFeatures, testFeatures])

    # Capturando a variável que identifica os dados de treino e de teste.

    train = features['train']

    # Eliminado a variável de identificação do Dataframe.

    features = features.drop('train', axis = 1)

    # Criando variável para armazenar o conjunto de dados transformados.

    featuresTransformed = None

    # Normalizando cada feature para uma unidade uniforme (vetor unitário).

    featuresTransformed = normalize(features, axis = 0)

    # Instanciando um objeto da classe PCA para criar os componentes.

    pca = PCA(n_components = nComponents)

    # Capturando os componentes.

    featuresTransformed = pca.fit_transform(featuresTransformed)

    # Criando um DataFrame com os resultados obtidos.

    featuresTransformed = pd.DataFrame(
        data    = featuresTransformed, 
        columns = ['PCA_' + str(i) for i in range(0, nComponents)]
    )

    # Atribuindo variável identificadora ao DataFrame transformado.

    featuresTransformed['train'] = train.values

    # Separando dados de treino e de teste transformados.

    trFeatures  = featuresTransformed[featuresTransformed['train'] == 1].drop('train', axis = 1)
    tstFeatures = featuresTransformed[featuresTransformed['train'] == 0].drop('train', axis = 1)

    # Retornando dados de treino e teste transformados.

    return trFeatures, tstFeatures

5.2 Data Munging - Preparando os dados para a modelagem preditiva

A partir da análise exploratória realizada, podemos observar que há alguns valores inconsistentes dentro do conjunto de dados. Para solucionar este problema, iremos substituí-los pelo valor mediano do grupo ao qual pertencem, isto é, do conjunto de mulheres com ou sem diabetes.

In [88]:
# Substituindo os registros, em que a glicose é 0, pelo valor mediano do grupo ao qual pertence 
# (grupo de indivíduos com ou sem diabetes).

data.loc[(data.glicose == 0) & (data.diabetes == 'No'), 'glicose'] = data [
    (data.glicose != 0) & (data.diabetes == 'No')
]['glicose'].median()

data.loc[(data.glicose == 0) & (data.diabetes == 'Yes'), 'glicose'] = data [
    (data.glicose != 0) & (data.diabetes == 'Yes')
]['glicose'].median()
In [89]:
# Substituindo os registros, em que a pressão sanguínea é 0, pelo valor mediano do grupo ao qual pertence 
# (grupo de indivíduos com ou sem diabetes).

data.loc[(data.pressao_sanguinea == 0) & (data.diabetes == 'No'), 'pressao_sanguinea'] = data [
    (data.pressao_sanguinea != 0) & (data.diabetes == 'No')
]['pressao_sanguinea'].median()

data.loc[(data.pressao_sanguinea == 0) & (data.diabetes == 'Yes'), 'pressao_sanguinea'] = data [
    (data.pressao_sanguinea != 0) & (data.diabetes == 'Yes')
]['pressao_sanguinea'].median()
In [90]:
# Substituindo os registros, em que a insulina é 0, pelo valor mediano do grupo ao qual pertence 
# (grupo de indivíduos com ou sem diabetes).

data.loc[(data.insulina == 0) & (data.diabetes == 'No'), 'insulina'] = data [
    (data.insulina != 0) & (data.diabetes == 'No')
]['insulina'].median()

data.loc[(data.insulina == 0) & (data.diabetes == 'Yes'), 'insulina'] = data [
    (data.insulina != 0) & (data.diabetes == 'Yes')
]['insulina'].median()
In [91]:
# Substituindo os registros, em que a BMI é 0, pelo valor mediano do grupo ao qual pertence 
# (grupo de indivíduos com ou sem diabetes).

data.loc[(data.bmi == 0) & (data.diabetes == 'No'), 'bmi'] = data [
    (data.bmi != 0) & (data.diabetes == 'No')
]['bmi'].median()

data.loc[(data.bmi == 0) & (data.diabetes == 'Yes'), 'bmi'] = data [
    (data.bmi != 0) & (data.diabetes == 'Yes')
]['bmi'].median()
In [92]:
# Substituindo os registros, em que a grossura da pele é 0, pelo valor mediano do grupo ao qual pertence 
# (grupo de indivíduos com ou sem diabetes).

data.loc[(data.grossura_pele == 0) & (data.diabetes == 'No'), 'grossura_pele'] = data [
    (data.grossura_pele != 0) & (data.diabetes == 'No')
]['grossura_pele'].median()

data.loc[(data.grossura_pele == 0) & (data.diabetes == 'Yes'), 'grossura_pele'] = data [
    (data.grossura_pele != 0) & (data.diabetes == 'Yes')
]['grossura_pele'].median()

5.3 Extraindo Features dos conjuntos de dados

Nesta etapa, iremos segmentar os registros em dados de treino e de teste.

In [93]:
# Criando conjunto de dados de treino e de teste.

trainFeatures, testFeatures, trainTarget, testTarget = train_test_split (
    data.drop('diabetes', axis = 1), data['diabetes'], test_size = 0.20
)
In [94]:
# Verificando as novas dimensões do DataFrame de treino.

trainFeatures.shape
Out[94]:
(614, 8)
In [95]:
# Verificando as novas dimensões do DataFrame de teste.

testFeatures.shape
Out[95]:
(154, 8)

5.4 Aplicando diferentes escalas as Features de Treino e de Teste

Iremos aplicar diferentes transformações, nas variáveis preditoras dos conjuntos de dados de treino e de teste.

In [96]:
# Aplicando a transformação MinMaxScaler, as Features do conjunto de dados de treino e de teste.

trainFeaturesMM, testFeaturesMM = dataTransform (
    train     = trainFeatures,
    test      = testFeatures,
    transform = 'MM'
)
In [97]:
# Aplicando a transformação StandardScaler, as Features do conjunto de dados de treino e de teste.

trainFeaturesSS, testFeaturesSS = dataTransform (
    train     = trainFeatures,
    test      = testFeatures,
    transform = 'SS'
)
In [98]:
# Aplicando a transformação Yeo-Johnson, as Features do conjunto de dados de treino e de teste.

trainFeaturesNormDistribuition, testFeaturesNormDistribuition = dataTransform (
    train     = trainFeatures,
    test      = testFeatures,
    transform = 'ND'
)
In [99]:
# Aplicando a transformação Normalize, as Features do conjunto de dados de treino e de teste.

trainFeaturesNormalized, testFeaturesNormalized = dataTransform (
    train     = trainFeatures,
    test      = testFeatures,
    transform = 'N'
)

5.5 Aplicando técnicas de Features Selection

Aplicaremos diferentes técnicas de Feature Selection, para determinar qual é a melhor combinação de variáveis preditoras a ser utilizada.

5.5.1 SelectKBest

Este método seleciona recursos de acordo com as k pontuações mais altas.

In [100]:
# Definindo qual conjunto de dados, já escalado, deve ser utilizado.

tFeatures = trainFeaturesMM

# Instanciando um objeto da classe SelectKBest, para selecionar as melhores variáveis preditoras.

skb = SelectKBest(chi2, k = 8)

# Capturando os scores das variáveis preditoras.

bestFeatuesSKB = skb.fit_transform(tFeatures, trainTarget)

# Capturando o nome das variáveis preditoras.

bfSkb = tFeatures.columns[skb.get_support()]

# Exibindo o nome das variáveis preditoras.

bfSkb
Out[100]:
Index(['num_gestacoes', 'glicose', 'pressao_sanguinea', 'grossura_pele',
       'insulina', 'bmi', 'indice_historico', 'idade'],
      dtype='object')
In [101]:
# Criando um DataFrame, com os scores obtidos para cada uma das Features, segundo a técnica utilizada.

sc = pd.Series(skb.scores_, index = tFeatures.columns)

# Capturando os scores das variáveis preditoras.

sc = sc[skb.get_support()]

# Ordenando o Dataframe com os scores.

sc = sc.sort_values(ascending = False)
In [102]:
# Plotando um gráfico de barras, dos scores gerados para as features, a partir da técnica utilizada.

plotBar (
    data        = sc,
    title       = 'Scores das melhores features com o SelectKBest', 
    yaxis       = 'Features', 
    xaxis       = 'Scores',
    orientation = 'h'
)

Segundo o método Select K Best, as variáveis glicose, insulina e idade são as mais importantes.

5.5.2 Information Gain

O Information gain ou Mutual information mede quanta informação a presença / ausência de um recurso contribui para fazer a previsão correta da variável target.

In [103]:
# Definindo qual conjunto de dados, já escalado, deve ser utilizado.

tFeatures = trainFeaturesMM

# Instanciando um objeto da classe mutual_info_classif.

bestFeatuesIG = mutual_info_classif(tFeatures, trainTarget, discrete_features = 'auto', n_neighbors = 3)

# Inserindo Scores obtidos em uma Série temporal.

scoreFeatures = pd.Series(bestFeatuesIG, index = tFeatures.columns)

# Capturando os scores das variáveis preditoras em ordem decrescente.

bfIg = scoreFeatures.sort_values(ascending = False)
In [104]:
# Plotando um gráfico de barras, dos scores gerados para as features, a partir da técnica utilizada.

plotBar (
    data        = bfIg,
    title       = 'Scores das melhores features com o Information Gain', 
    yaxis       = 'Features', 
    xaxis       = 'Scores', 
    orientation = 'h'
)

Segundo o método Information Gain, as variáveis Insulina, grossura_pele e glicose são as mais importantes.

In [105]:
# Capturando o nome das variáveis preditoras.

bfIg = bfIg.index

# Exibindo o nome das variáveis preditoras.

bfIg
Out[105]:
Index(['insulina', 'grossura_pele', 'glicose', 'idade', 'bmi',
       'pressao_sanguinea', 'indice_historico', 'num_gestacoes'],
      dtype='object')

5.5.3 ANOVA F-value

Se os recursos forem categóricos, calcularemos uma estatística qui-quadrado entre cada recurso e a variável target. No entanto, se os recursos forem quantitativos, calcularemos a ANOVA F-Value entre cada recurso e a variável target.

As pontuações do F-Value examinam se, quando agrupamos a característica numérica pela variável target, as médias para cada grupo se tornam significativamente diferentes.

In [106]:
# Definindo qual conjunto de dados, já escalado, deve ser utilizado.

tFeatures = trainFeaturesMM

# Instanciando um objeto da classe SelectKBest para selecionar as melhores variáveis 
# preditoras a partir dos scores ANOVA F-Values.

skb = SelectKBest(f_classif, k = 8)

# Capturando as variáveis preditoras.

bestFeatuesANOVA = skb.fit_transform(tFeatures, trainTarget)

# Capturando o nome das variáveis preditoras.

bfAnova = tFeatures.columns[skb.get_support()]

# Exibindo o nome das variáveis preditoras.

bfAnova
Out[106]:
Index(['num_gestacoes', 'glicose', 'pressao_sanguinea', 'grossura_pele',
       'insulina', 'bmi', 'indice_historico', 'idade'],
      dtype='object')
In [107]:
# Criando uma Série Temporal com os scores obtidos para cada uma das Features segundo a técnica utilizada.

sc = pd.Series(skb.scores_, index = tFeatures.columns)

# Capturando os scores das variáveis preditoras.

sc = sc[skb.get_support()]

# Ordenando a Série Temporal em ordem decrescente dos scores.

sc = sc.sort_values(ascending = False)
In [108]:
# Plotando um gráfico de barras, dos scores gerados para as features, a partir da técnica utilizada.

plotBar (
    data        = sc,
    title       = 'Scores das melhores features com o ANOVA F-value', 
    yaxis       = 'Features', 
    xaxis       = 'Scores', 
    orientation = 'h'
)

Segundo o método ANOVA F-Value, as variáveis glicose, insulina e grossura_pele são as mais importantes.

5.5.4 Forward Selection

O Forward Selection é um método iterativo, no qual começamos sem ter nenhum recurso no modelo. A cada iteração, adicionamos uma variável que melhora o modelo e efetuamos este procedimento até que a performance do modelo pare de evoluir.

A seleção de recursos começa avaliando todas as variáveis individualmente, e seleciona aquela que gera o algoritmo com o melhor desempenho, de acordo com um critério de avaliação predefinido. Em seguida, se avalia todas as combinações possíveis das variáveis já selecionadas e dos recursos ainda não escolhidos para definir a combinação que produz o algoritmo com a melhor performance, com base nos mesmos critérios predefinidos.

In [109]:
# Definindo qual conjunto de dados, já escalado, deve ser utilizado.

tFeatures = trainFeaturesNormDistribuition

# Instanciando um objeto da classe SFS para selecionar as melhores variáveis 
# preditoras segundo sua acurácia, utilizando o algoritmo XGBClassifer.

sfs = SFS (
    estimator  = xgb.XGBClassifier(), 
    k_features = 8,
    forward    = True, 
    floating   = False, 
    verbose    = 2,
    scoring    = 'accuracy',
    cv         = 3
)

# Capturando as variáveis preditoras.

sfs = sfs.fit(
    X = tFeatures, 
    y = trainTarget
)
[Parallel(n_jobs=1)]: Using backend SequentialBackend with 1 concurrent workers.
[Parallel(n_jobs=1)]: Done   1 out of   1 | elapsed:    0.5s remaining:    0.0s
[Parallel(n_jobs=1)]: Done   8 out of   8 | elapsed:    1.1s finished

[2020-10-19 08:33:18] Features: 1/8 -- score: 0.8225091662681333[Parallel(n_jobs=1)]: Using backend SequentialBackend with 1 concurrent workers.
[Parallel(n_jobs=1)]: Done   1 out of   1 | elapsed:    0.0s remaining:    0.0s
[Parallel(n_jobs=1)]: Done   7 out of   7 | elapsed:    0.6s finished

[2020-10-19 08:33:18] Features: 2/8 -- score: 0.8729953770125937[Parallel(n_jobs=1)]: Using backend SequentialBackend with 1 concurrent workers.
[Parallel(n_jobs=1)]: Done   1 out of   1 | elapsed:    0.0s remaining:    0.0s
[Parallel(n_jobs=1)]: Done   6 out of   6 | elapsed:    0.5s finished

[2020-10-19 08:33:19] Features: 3/8 -- score: 0.8909214092140921[Parallel(n_jobs=1)]: Using backend SequentialBackend with 1 concurrent workers.
[Parallel(n_jobs=1)]: Done   1 out of   1 | elapsed:    0.0s remaining:    0.0s
[Parallel(n_jobs=1)]: Done   5 out of   5 | elapsed:    0.4s finished

[2020-10-19 08:33:19] Features: 4/8 -- score: 0.8893113342898135[Parallel(n_jobs=1)]: Using backend SequentialBackend with 1 concurrent workers.
[Parallel(n_jobs=1)]: Done   1 out of   1 | elapsed:    0.0s remaining:    0.0s
[Parallel(n_jobs=1)]: Done   4 out of   4 | elapsed:    0.3s finished

[2020-10-19 08:33:20] Features: 5/8 -- score: 0.8958233699984058[Parallel(n_jobs=1)]: Using backend SequentialBackend with 1 concurrent workers.
[Parallel(n_jobs=1)]: Done   1 out of   1 | elapsed:    0.0s remaining:    0.0s
[Parallel(n_jobs=1)]: Done   3 out of   3 | elapsed:    0.2s finished

[2020-10-19 08:33:20] Features: 6/8 -- score: 0.9006934481109518[Parallel(n_jobs=1)]: Using backend SequentialBackend with 1 concurrent workers.
[Parallel(n_jobs=1)]: Done   1 out of   1 | elapsed:    0.0s remaining:    0.0s
[Parallel(n_jobs=1)]: Done   2 out of   2 | elapsed:    0.1s finished

[2020-10-19 08:33:20] Features: 7/8 -- score: 0.8958074286625219[Parallel(n_jobs=1)]: Using backend SequentialBackend with 1 concurrent workers.
[Parallel(n_jobs=1)]: Done   1 out of   1 | elapsed:    0.0s remaining:    0.0s
[Parallel(n_jobs=1)]: Done   1 out of   1 | elapsed:    0.0s finished

[2020-10-19 08:33:20] Features: 8/8 -- score: 0.8827833572453372
In [110]:
# Capturando o nome das variáveis preditoras.

bfSfs = tFeatures.columns[list(sfs.k_feature_idx_)]

# Exibindo o nome das variáveis preditoras.

bfSfs
Out[110]:
Index(['num_gestacoes', 'glicose', 'pressao_sanguinea', 'grossura_pele',
       'insulina', 'bmi', 'indice_historico', 'idade'],
      dtype='object')
In [111]:
# Capturando os resultados obtidos pela Técnica Forward Selection.

sc = pd.DataFrame(sfs.get_metric_dict())

# Capturando os scores e o nome das Features, gerados a cada busca.

sc = sc.loc[['cv_scores', 'feature_names'], :].transpose()

# Capturando o nome das features utilizadas em cada avaliação.

featureNames = sc.feature_names

# Criando índices com o número de Features utilizadas em cada avaliação.

columns = [str(i) + ' Feature' if i == 1 else str(i) + ' Features' for i in range(1, sc.shape[0] + 1)]

# Remodelando os dados do DataFrame para serem plotados.

fs = pd.DataFrame()

for i in range(1, sc.shape[0] + 1):

    # Atribui os primeiros scores ao DataFrame, caso esteja vazio.

    if sc.empty:
        fs = pd.DataFrame(sc['cv_scores'][i], columns = [columns[i - 1]])
    else:
        fs[columns[i - 1]] = sc['cv_scores'][i]
In [112]:
# Plotando os scores da acurácia, obtida pelas features selecionadas em cada fase de busca, segundo a técnica Forward Selection.

plotBoxplot (
    data   = fs,
    title  = 'Acurácia das melhores Features encontradas pelo técnica Forward Selection',
    xaxis  = 'Features selecionadas'
)
In [113]:
# Transpondo DataFrame.

fs = fs.transpose()

# Criando uma nova coluna, com os nomes das Features utilizadas, em cada avaliação no DataFrame.

fs['featuresNames'] = [', '.join(f) for f in featureNames]

# Exibindo o nome das features utilizadas em cada avaliação.

fs[['featuresNames']]
Out[113]:
featuresNames
1 Feature insulina
2 Features insulina, idade
3 Features glicose, insulina, idade
4 Features num_gestacoes, glicose, insulina, idade
5 Features num_gestacoes, glicose, insulina, bmi, idade
6 Features num_gestacoes, glicose, grossura_pele, insulin...
7 Features num_gestacoes, glicose, grossura_pele, insulin...
8 Features num_gestacoes, glicose, pressao_sanguinea, gro...

O uso das 4 ou 5 variáveis selecionadas gera os maiores scores para a acurácia.

5.5.5 Extra Trees Classifier

O Extremely Randomized Trees Classifier (Extra Trees Classifier) é um tipo de técnica de aprendizagem de conjunto que agrega os resultados de várias árvores de decisão descorrelacionadas coletadas em uma “floresta” para produzir seu resultado de classificação. Em conceito, é muito semelhante a um Classificador Random Forest e só difere na forma de construção das árvores de decisão na floresta.

Cada árvore de decisão na floresta de árvores extras é construída a partir da amostra de treinamento original. Então, em cada nó de teste, cada árvore é fornecida com uma amostra aleatória de k recursos do conjunto de recursos a partir do qual cada árvore de decisão deve selecionar o melhor recurso para dividir os dados com base em alguns critérios matemáticos (normalmente o índice de Gini). Essa amostra aleatória de recursos leva à criação de várias árvores de decisão não correlacionadas.

Para realizar a seleção de características usando a estrutura de floresta acima, durante a construção da floresta, para cada característica, a redução total normalizada nos critérios matemáticos usados ​​na decisão da característica de divisão (Índice de Gini se o Índice de Gini for usado na construção de floresta) é computado. Esse valor é chamado de Importância Gini do recurso. Para realizar a seleção de recursos, cada recurso é ordenado em ordem decrescente de acordo com a Importância Gini de cada recurso e o usuário seleciona os k principais recursos de acordo com sua escolha.

In [114]:
# Definindo qual conjunto de dados, já escalado, deve ser utilizado.

tFeatures = trainFeaturesMM

# Instanciando um objeto da classe ExtraTreesClassifier.

modelETC = ExtraTreesClassifier()

# Computando os scores de cada feature.

modelETC.fit (
    X = tFeatures, 
    y = trainTarget
)

# Inserindo Scores obtidos em uma Série Temporal.

featuresImpETC = pd.Series(data = modelETC.feature_importances_, index = tFeatures.columns)

# Ordeando o nome das variáveis preditoras segundo seu score em ordem decrescente.

bfEtc = featuresImpETC.sort_values(ascending = False)
In [115]:
# Plotando um gráfico de barras, dos scores gerados para as features, a partir da técnica utilizada.

plotBar (
    data        = bfEtc, 
    title       = 'Scores das melhores features com o Extra Trees Classifier', 
    yaxis       = 'Features', 
    xaxis       = 'Scores', 
    orientation = 'h'
)

Segundo o método Extra Trees Classifier, as variáveis insulina, grossura_pele e glicose são as mais importantes.

In [116]:
# Capturando o nome das variáveis preditoras.

bfEtc = bfEtc.index

# Exibindo o nome das variáveis preditoras.

bfEtc
Out[116]:
Index(['insulina', 'glicose', 'grossura_pele', 'bmi', 'idade',
       'indice_historico', 'num_gestacoes', 'pressao_sanguinea'],
      dtype='object')

5.5.6 Random Forest Importance

O Random Forest, é um dos algoritmos de aprendizado de máquina mais populares. É um dos mais bem-sucedidos porque fornece, em geral, um bom desempenho preditivo, baixo overfitting e é de fácil interpretabilidade.

Essa interpretabilidade é dada pela facilidade de se derivar a importância de cada variável na árvore de decisão. Em outras palavras, é fácil calcular o quanto cada variável está contribuindo para a decisão do modelo.

O Random Forest consiste em 4-12 centenas de árvores de decisão, cada uma delas construída sobre uma extração aleatória das observações do conjunto de dados e uma extração aleatória das características. Nem toda árvore vê todas as características ou todas as observações, e isso garante que as árvores sejam descorrelacionadas e, portanto, menos sujeitas a sobreajuste. Cada árvore também é uma sequência de perguntas sim-não com base em um único recurso ou em uma combinação de recursos. Em cada nó (isto é em cada questão), os três dividem o conjunto de dados em 2 depósitos, cada um deles hospedando observações que são mais semelhantes entre si e diferentes das do outro bloco. Portanto, a importância de cada recurso é derivada do quão "puro" cada um dos blocos é.

Para classificação, a medida de impureza é a impureza de Gini ou o ganho / entropia de informação. Para regressão, a medida de impureza é a variância. Portanto, ao treinar uma árvore, é possível calcular o quanto cada recurso diminui a impureza. Quanto maior for a diminuição da impureza que um recurso gerar, mais importante ele será. Em florestas aleatórias, a diminuição da impureza de cada recurso pode ser calculada em média entre as árvores para determinar a importância final da variável.

In [117]:
# Definindo qual conjunto de dados, já escalado, deve ser utilizado.

tFeatures = trainFeaturesMM

# Instanciando um objeto da classe RandomForestClassifier.

rfImp = RandomForestClassifier (
    n_estimators = 200,
    random_state = 0
)

# Treinando o classificador com o conjunto de dados de treino.

rfImp.fit(
    X = tFeatures, 
    y = trainTarget
)

# Prevendo os scores das features dos dados de treino.

pred = rfImp.predict(tFeatures)

# Convertendo os scores para um DataFrame.

featuresImpRf = pd.Series(data = rfImp.feature_importances_, index = tFeatures.columns)

# Capturando os scores de cada uma das features.

bfRf = featuresImpRf.nlargest(8)
In [118]:
# Plotando um gráfico de barras, dos scores gerados para as features, a partir da técnica utilizada.

plotBar (
    data        = bfRf,
    title       = 'Scores das melhores features com o Random Forest', 
    yaxis       = 'Features', 
    xaxis       = 'Scores', 
    orientation = 'h'
)

Segundo o método Random Forest, as variáveis insulina, grossura_pele e glicose são as mais importantes.

In [119]:
# Capturando o nome das variáveis preditoras.

bfRf = bfRf.index

# Exibindo o nome das variáveis preditoras.

bfRf
Out[119]:
Index(['insulina', 'glicose', 'grossura_pele', 'bmi', 'idade',
       'indice_historico', 'pressao_sanguinea', 'num_gestacoes'],
      dtype='object')

5.5.7 PCA

A Análise de componente principal (Principal Component Analysis - PCA) é uma técnica de redução de dimensionalidade linear que pode ser utilizada para extrair informações de um espaço de alta dimensão projetando-as em um subespaço de dimensão inferior. Ele tenta preservar as partes essenciais que têm mais variação dos dados e remover as partes não essenciais com menos variação. As dimensões nada mais são do que recursos que representam os dados.

Uma coisa importante a se notar sobre o PCA é que é uma técnica de redução de dimensionalidade não supervisionada. Você pode agrupar os pontos de dados semelhantes com base na correlação de recursos entre eles sem qualquer supervisão (ou rótulos).

In [120]:
# Aplicando a técnica PCA, para criar 8 Componentes, a partir dos dados de treino e de teste.

trainFeaturesPCA, testFeaturesPCA =  pcaTransform(train = trainFeatures, test = testFeatures)

6. Modelagem Preditiva

6.1 Criando funções auxiliares

Iremos definir algumas funções, para executar as etapas de modelagem preditiva.

In [121]:
# Definindo uma função, para treinar diferentes algoritmos, e prever a variável Target de um conjunto de dados.

def classifiersTraining(features, tTarget, printMeans = True, scoring = 'accuracy'):
    
    # Definindo os valores do seed e do número de folds.
    
    num_folds = 10
    seed      = 100

    # Criando uma lista, para armazenar os modelos que serão utilizados.

    models = []

    # Criando Listas para armazenar os resultados e os nomes de cada um dos algoritmos testados.

    results = []
    names   = []

    # Criando um Dataframe para armazenar a média e o desvio-padrão de cada um dos algoritmos testados.

    means   = pd.DataFrame(columns = ['mean', 'std'])

    # Adicionando os modelos a lista.

    models.append(('LR'      , LogisticRegression()            ))
    models.append(('LDA'     , LinearDiscriminantAnalysis()    ))
    models.append(('QDA'     , QuadraticDiscriminantAnalysis() ))
    models.append(('RC'      , RidgeClassifierCV()             ))
    models.append(('NB'      , GaussianNB()                    ))
    models.append(('KNN'     , KNeighborsClassifier()          ))
    models.append(('CART'    , DecisionTreeClassifier()        ))
    models.append(('AdaBoost', AdaBoostClassifier()            ))
    models.append(('GB'      , GradientBoostingClassifier()    ))
    models.append(('SVM'     , SVC()                           ))
    models.append(('RF'      , RandomForestClassifier()        ))
    models.append(('XGBoost' , xgb.XGBClassifier()             ))

    # Avaliando cada um dos modelos da lista de modelos.

    for name, model in models:
        
        # Instanciando um objeto da classe Kfold para criar os folds.

        kfold = KFold(n_splits = num_folds, random_state = seed)
        
        # Treinando o modelo com Cross Validation.

        cv_results = cross_val_score(model, features, tTarget, cv = kfold, scoring = scoring)
        
        # Adicionando os resultados gerados na lista de resultados.

        results.append(cv_results)
        
        # Adicionando o nome do modelo avaliado na lista de nomes.

        names.append(name)

        # Adicionando a média e o desvio-padrão, dos resultados gerados pelo modelo analisado, ao Dataframe de médias.

        means = means.append (
            pd.DataFrame (
                data    = [[cv_results.mean(), cv_results.std()]], 
                columns = ['mean', 'std'], 
                index   = [name]
            )
        )

        # Imprime uma mensagem, contendo os resultados obtidos ao fim do treinamento, de cada um dos modelos.

        if printMeans:

            # Cria a mensagem a ser impressa.

            msg = "%s: %f (%f)" % (name, cv_results.mean(), cv_results.std())
            
            # Imprime a mensagem.

            print(msg)

    # Cria um DataFrame, com os resultados obtidos por cada um dos modelos avaliados.

    results = pd.DataFrame(np.transpose(results), columns = names)

    # Retorna o DataFrame, com os resultados e com as médias geradas.
    
    return (results, means)
In [122]:
# Definindo uma função, para realizar a plotagem de Confusions Matrix.

def plotConfusionMatrix(data, labels, figsize = (6, 6), fontScale = 1.2, 
                        title = 'Confusion Matrix', xlabel = 'Actual', ylabel = 'Predicted'):

    # Definindo a área de plotagem e suas dimensões.

    _, ax = plt.subplots(figsize = figsize)

    # Definindo o tamanho da fonte utilizada no gráfico.

    sns.set(font_scale = fontScale)

    # Criando Heatmap para representar a Confusion Matrix.

    ax = sns.heatmap (
        data       = data,
        annot      = True,
        cmap       = 'Blues',
        linewidths = 5,
        cbar       = False,
        fmt        = 'd'
    ) 

    # Definindo as labels e o título do gráfico. 

    ax.set_xlabel(xlabel)
    ax.set_ylabel(ylabel) 
    ax.set_title(title)

    # Definindo as ticklabels do gráfico.

    ax.xaxis.set_ticklabels(labels)
    ax.yaxis.set_ticklabels(labels);
In [123]:
# Definindo uma função, para realizar o cálculo do Intervalo de Confiança, da acurácia 
# e do erro de modelos preditivos de classificação.

def CI(score, nElements,  ci = .95):

    # Define o Z-score, a ser utilizado para o Intervalo de Confiança selecionado.
    
    z = {
        .90  : 1.645,      # Para Intervalos com 90% de Confiança.
        .95  : 1.96,       # Para Intervalos com 95% de Confiança.
        .98  : 2.326,      # Para Intervalos com 98% de Confiança.
        .99  : 2.576,      # Para Intervalos com 99% de Confiança.
        .995 : 2.807,      # Para Intervalos com 99.5% de Confiança.
        .999 : 3.291       # Para Intervalos com 99.9% de Confiança.
    }

    # Calculando o range de variação do Intervalo.

    interval = z.get(ci) * np.sqrt( (score * (1 - score)) / nElements)

    # Retornando o Intervalo de Confiança obtido.

    return score - interval, score + interval
In [124]:
# Definindo uma função, para criar uma Confusion Matrix.

def confusionMatrix(yTrue, yPred, labelPositive = 'Yes', labelNegative = 'No', classError = True):

    # Convertendo arrays para o tipo de dado categórico.

    yTrue = pd.Categorical(values = yTrue, categories = labels)
    yPred = pd.Categorical(values = yPred, categories = labels)

    # Transformando arrays em Séries Temporais.

    yPred = pd.Series(data = yPred, name = 'Predicted')
    yTrue = pd.Series(data = yTrue, name = 'Actual')

    # Criando a Confusion Matrix.

    cm = pd.crosstab(index = yPred, columns = yTrue, dropna = False)

    # Calculando os erros das classes da Confusion Matrix.

    if classError:
        
        # Capturando cada um dos valores da Confusion Matrix.

        truePositve, falsePositive, falseNegative, trueNegative = np.array(cm).ravel()

        # Criando um DataFrame contendo os erros das classes.

        ce = pd.DataFrame (
            data = [
                falsePositive / (truePositve + falsePositive),
                1 - trueNegative / (trueNegative + falseNegative)
            ],
            columns = ['classError'],
            index   = labels
        )

        # Inserindo no DataFrame, as colunas da Confusion Matrix.

        for c in range(cm.shape[1] - 1, -1, -1):
            
            # Inserindo as colunas no DataFrame.

            ce.insert(loc = 0, column = labels[c], value = cm[labels[c]])

        # Atribuindo índices e colunas ao DataFrame.
        
        ce.index   = pd.Series(ce.index, name = 'Predicted')
        ce.columns = pd.Series(ce.columns, name = 'Actual')

        # Retornando a Confusion Matrix com o erro das classes.
        
        return ce

    # Retornando Confusion Matrix.

    return cm
In [125]:
# Definindo uma função, para calcular as métricas baseadas na Confusion Matrix.

def getClassificationMetrics(yTrue, predProb, labelPositive = 'Yes', labelNegative = 'No'):

    # Binarizando os scores obtidos nas previsões.
    
    yPred = [labelPositive if v >= 0.5 else labelNegative for v in predProb]
    
    # Convertendo arrays para o tipo categórico.

    labels = [labelPositive, labelNegative]

    yTrue = pd.Categorical(values = yTrue, categories = labels)
    yPred = pd.Categorical(values = yPred, categories = labels)

    # Convertendo arrays para o tipo numérico. 

    yNTrue = [1 if v == labelPositive else 0 for v in yTrue]
    yNPred = [1 if v == labelPositive else 0 for v in yPred]

    # Transformando arrays em Séries Temporais.

    yPred = pd.Series(data = yPred, name = 'Predicted')
    yTrue = pd.Series(data = yTrue, name = 'Actual')

    # Criando a Confusion Matrix.

    cm = confusionMatrix(yTrue, yPred, labelPositive = labelPositive, labelNegative = labelNegative, classError = False)

    # Capturando cada um dos valores da Confusion Matrix.

    truePositve, falsePositive, falseNegative, trueNegative = np.array(cm).ravel()

    # Calculando as métricas.

    accuracy     = accuracy_score(yTrue, yPred)
    accuracyCI   = CI(accuracy_score(yTrue, yPred), len(yTrue))
    kappa        = cohen_kappa_score(yTrue, yPred)
    sensitivity  = recall_score(yNTrue, yNPred)
    specificity  = trueNegative /(trueNegative + falsePositive)
    prevalence   = (truePositve + falseNegative) / len(yTrue)
    ppv          = (sensitivity * prevalence) /((sensitivity * prevalence) + ((1 - specificity) * (1 - prevalence)))
    npv          = (specificity * (1 - prevalence)) / (((1 - sensitivity) * prevalence) + ((specificity) * (1 - prevalence)))
    precision    = precision_score(yNTrue, yNPred)
    avgPrecision = average_precision_score(yNTrue, yNPred)
    dRate        = truePositve / len(yTrue)
    dPrevalence  = (truePositve + falsePositive) / len(yTrue)
    f1           = f1_score(yNTrue, yNPred)
    rocAuc       = roc_auc_score(yNTrue, predProb)
    error        = 1 - accuracy_score(yTrue, yPred)
    errorCI      = CI(error, len(yTrue))
    bAccuracy    = balanced_accuracy_score(yTrue, yPred)

    # Criando um DataFrame, com o resultado das métricas calculadas.

    metrics = pd.DataFrame([{
        'Accuracy'            : accuracy,     # Determina a precisão geral prevista do modelo.
        '95% CI for Accuracy' : accuracyCI,   # Determina um intervalo de confiança de 95% para a acurácia.
        'Kappa'               : kappa,        # Determina o coeficiente de Kappa.
        'Recall (Sensitivity)': sensitivity,  # Determina a proporção de registros positivos que foram classificados 
                                              # pelo algoritmo como positivos.
        'Specificity'         : specificity,  # Determina a proporção de registros negativos que foram classificados 
                                              # pelo algoritmo como negativos.
        'Pos Pred Value'      : ppv,          # Determina a porcentagem de positivos previstos que são realmente positivos.
        'Neg Pred Value'      : npv,          # Determina a porcentagem de negativos previstos que são realmente negativos.
        'Precision'           : precision,    # Determina a proporção de classificações positivas, que realmente são positivas.
        'Avarage Precision'   : avgPrecision, # Determina a precisão como a média ponderada de precisões 
                                              # alcançadas em cada limite.
        'Prevalence'          : prevalence,   # Determina a frequência com que a classe positiva realmente 
                                              # ocorre em nossa amostra.
        'Detection Rate'      : dRate,        # Determina a proporção de classificações positivas feitas corretamente em relação 
                                              # a todas as previsões feitas.
        'Detection Prevalence': dPrevalence,  # Determina o número de previsões positivas como uma proporção de 
                                              # todas as previsões.
        'F1'                  : f1,           # Determina a média Harmônica entre a precision e o recall do modelo.
        'ROC AUC'             : rocAuc,       # Determina a medida de separabilidade ROC. Ela indica o quanto o modelo é 
                                              # capaz de distinguir as classes.   
        'Error'               : error,        # Determina o erro do modelo em relação a sua acurácia.
        '95% CI for Error'    : errorCI,      # Determina um intervalo de confiança de 95% para o erro.
        'Balanced Accuracy'   : bAccuracy,    # Determina a acurácia do modelo balanceada pelos tamanhos das classes.
        'Positive Class'      : labelPositive # Define qual classe é a classe positiva.
    }], index = ['Metrics']).transpose()

    # Retornando o DataFrame, com as métricas obtidas.

    return metrics
In [126]:
# Definindo uma função para salvar um modelo preditivo já treinado.

def saveModel(name, model, fold = 'content/outputs/', ext = '.sav'):

    # Definindo o diretório e o nome do arquivo que será utilizado para salvar o modelo.

    dir = fold + name + ext

    # Salvando o modelo especificado.

    pickle.dump(model, open(dir, 'wb'))

    # Imprimindo mensagem de sucesso.

    print("Modelo salvo!")
In [127]:
# Definindo uma função para carregar um modelo preditivo já treinado.

def loadModel(name, fold = 'content/outputs/', ext = '.sav'):

    # Definindo o diretório e o nome do arquivo que será utilizado para carregar o modelo.

    dir = fold + name + ext

    # Imprimindo mensagem de sucesso.

    print("Modelo carregado!")

    # Carregando o modelo especificado.

    return pickle.load(open(dir, 'rb'))

6.2 Criando modelos preditivos e avaliando suas Performances

In [128]:
# Treinando classificadores, a partir dos componentes criados pela técnica PCA.

resultsPCA = classifiersTraining (
    features = trainFeaturesPCA, 
    tTarget  = trainTarget
)
LR: 0.658117 (0.050639)
LDA: 0.786779 (0.058771)
QDA: 0.747515 (0.057524)
RC: 0.737837 (0.056568)
NB: 0.749154 (0.065120)
KNN: 0.843654 (0.049898)
CART: 0.770465 (0.048540)
AdaBoost: 0.768614 (0.044681)
GB: 0.822475 (0.034413)
SVM: 0.842068 (0.051975)
RF: 0.833950 (0.046860)
XGBoost: 0.830672 (0.065805)
In [129]:
# Plotando os scores, da acurácia dos classificadores treinados, em boxplots.

plotBoxplot(data = resultsPCA[0])

O algoritmo SVM, foi o que obteve a melhor acurácia, para o conjunto de componentes do PCA.

In [130]:
# Treinando classificadores, a partir da escala, e da técnica de Feature Selection utilizada.

resultsMM = classifiersTraining (
    features = trainFeaturesMM, 
    tTarget  = trainTarget
)
LR: 0.783421 (0.055301)
LDA: 0.786779 (0.058771)
QDA: 0.747515 (0.057524)
RC: 0.783501 (0.055374)
NB: 0.768720 (0.059969)
KNN: 0.811185 (0.053956)
CART: 0.863221 (0.040036)
AdaBoost: 0.858355 (0.045422)
GB: 0.884373 (0.051152)
SVM: 0.798176 (0.061504)
RF: 0.879482 (0.048503)
XGBoost: 0.889291 (0.053237)
In [131]:
# Plotando os scores, da acurácia dos classificadores treinados, em boxplots.

plotBoxplot(data = resultsMM[0])

O algoritmo XGBoost, foi o que obteve a melhor acurácia, para o conjunto dados transformados pelo algoritmo MinMaxScaler.

In [132]:
# Treinando classificadores, a partir da escala, e da técnica de Feature Selection utilizada.

resultsSS = classifiersTraining (
    features = trainFeaturesSS, 
    tTarget  = trainTarget
)
LR: 0.788366 (0.056438)
LDA: 0.786779 (0.058771)
QDA: 0.747515 (0.057524)
RC: 0.781861 (0.054594)
NB: 0.768720 (0.059969)
KNN: 0.801428 (0.051356)
CART: 0.863221 (0.040101)
AdaBoost: 0.858355 (0.045422)
GB: 0.884347 (0.052158)
SVM: 0.842147 (0.042752)
RF: 0.872898 (0.046106)
XGBoost: 0.887652 (0.054087)
In [133]:
# Plotando os scores, da acurácia dos classificadores treinados, em boxplots.

plotBoxplot(data = resultsSS[0])

O algoritmo Random Forest, foi o que obteve a melhor acurácia, para o conjunto dados transformados pelo algoritmo StandardScaler.

In [134]:
# Treinando classificadores, a partir da escala, e da técnica de Feature Selection utilizada.

resultsND = classifiersTraining (
    features = trainFeaturesNormDistribuition, 
    tTarget  = trainTarget
)
LR: 0.803014 (0.037689)
LDA: 0.803014 (0.042205)
QDA: 0.827472 (0.046279)
RC: 0.804601 (0.038920)
NB: 0.807879 (0.038058)
KNN: 0.824167 (0.046526)
CART: 0.861608 (0.038761)
AdaBoost: 0.858355 (0.045422)
GB: 0.884373 (0.051152)
SVM: 0.848652 (0.039546)
RF: 0.879455 (0.052136)
XGBoost: 0.889291 (0.056184)
In [135]:
# Plotando os scores, da acurácia dos classificadores treinados, em boxplots.

plotBoxplot(data = resultsND[0])

O algoritmo Random Forest, foi o que obteve a melhor acurácia, para o conjunto dados transformados pelo algoritmo Box-Cox.

In [136]:
# Treinando classificadores, a partir da escala, e da técnica de Feature Selection utilizada.

resultsNorm = classifiersTraining (
    features = trainFeaturesNormalized, 
    tTarget  = trainTarget
)
LR: 0.658117 (0.050639)
LDA: 0.786779 (0.058771)
QDA: 0.747515 (0.057524)
RC: 0.737837 (0.056568)
NB: 0.768720 (0.059969)
KNN: 0.843654 (0.049898)
CART: 0.858382 (0.051585)
AdaBoost: 0.858355 (0.045422)
GB: 0.882760 (0.048693)
SVM: 0.842068 (0.051975)
RF: 0.884347 (0.050312)
XGBoost: 0.887652 (0.054087)
In [137]:
# Plotando os scores, da acurácia dos classificadores treinados, em boxplots.

plotBoxplot(data = resultsNorm[0])

O algoritmo Random Forest, foi o que obteve a melhor acurácia, para o conjunto dados transformados pelo algoritmo Normalize.

6.3 Realizando previsões para o conjunto de dados de teste

6.3.1 Otimizando Classificadores

Agora que já testamos diferentes algoritmos com diversas escalas, iremos escolher os melhores modelos criados e otimizar seus parâmetros.

6.3.1.1 Algoritmo Logistic Regression

Iremos buscar pelos melhores parâmetros, para criar um modelo com o algoritmo de Regressão Logística.

In [138]:
# Definindo qual conjunto de dados de treino, já escalado, deve ser utilizado e a sua variável target.

trainX = trainFeaturesNormalized
trainY = trainTarget

# Definindo qual conjunto de dados de teste, já escalado, deve ser utilizado e a sua variável target.

testX = testFeaturesNormalized
testY = testTarget

# Definindo os valores que devem ser testados, em cada um dos parâmetros do modelo especificado.

paramGrid = dict (
    penalty      = ['l1', 'l2'],
    C            = [13, 14, 15, 16, 17, 18, 19],
    solver       = ['lbfgs', 'liblinear'],
    random_state = [0],
    tol          = [0.0000025, 0.000005, 0.00001, 0.000025],
    max_iter     = [60, 70, 80, 90, 100, 110, 150]
)

# Criando uma instância da classe do modelo de Regressão Logística.

model = LogisticRegression()

# Criando o grid, para fazer a busca dos melhores parâmetros para o modelo.

grid = GridSearchCV(estimator = model, param_grid = paramGrid, cv = 10, verbose = True, n_jobs = -1)

# Buscando pelos melhores parâmetros para o modelo.

grid.fit(trainX, trainY)

# Exibindo a configuração, do melhor modelo treinado.

print("\n" + "Melhores Parâmetros para o Modelo:" + "\n\n", grid.best_estimator_)
Fitting 10 folds for each of 784 candidates, totalling 7840 fits
[Parallel(n_jobs=-1)]: Using backend LokyBackend with 16 concurrent workers.
[Parallel(n_jobs=-1)]: Done  18 tasks      | elapsed:    1.3s
[Parallel(n_jobs=-1)]: Done 352 tasks      | elapsed:    1.7s
[Parallel(n_jobs=-1)]: Done 7228 tasks      | elapsed:    6.3s
Melhores Parâmetros para o Modelo:

 LogisticRegression(C=15, max_iter=60, penalty='l1', random_state=0,
                   solver='liblinear', tol=2.5e-06)
[Parallel(n_jobs=-1)]: Done 7840 out of 7840 | elapsed:    6.6s finished
In [139]:
# Criando o modelo, com a melhor configuração encontrada.

classifierLR = grid.best_estimator_

# Treinando o modelo com os dados de treino.

classifierLR.fit(X = trainX, y = trainY)
Out[139]:
LogisticRegression(C=15, max_iter=60, penalty='l1', random_state=0,
                   solver='liblinear', tol=2.5e-06)
In [140]:
# Calculando a acurácia do modelo para o conjunto de dados de treino.

scoreTrainLR = accuracy_score(trainY, classifierLR.predict(trainX))

# Visualizando o resultado.

print('Acurácia para os dados de treino: ' + str(scoreTrainLR))
Acurácia para os dados de treino: 0.7947882736156352
In [141]:
# Calculando a acurácia do modelo para o conjunto de dados de teste.

scoreTestLR = accuracy_score(testY, classifierLR.predict(testX))

# Visualizando o resultado.

print('Acurácia  para os dados de teste: ' + str(scoreTestLR))
Acurácia  para os dados de teste: 0.7467532467532467
6.3.1.2 Algoritmo Random Forest

Iremos buscar pelos melhores parâmetros, para criar um modelo com o algoritmo Random Forest.

In [142]:
# Definindo qual conjunto de dados de treino, já escalado, deve ser utilizado e a sua variável target.

trainX = trainFeaturesNormDistribuition
trainY = trainTarget

# Definindo qual conjunto de dados de teste, já escalado, deve ser utilizado e a sua variável target.

testX = testFeaturesNormDistribuition
testY = testTarget

# Definindo os valores que devem ser testados, em cada um dos parâmetros do modelo especificado.

paramGrid = dict (
    n_estimators      = [100, 106, 108, 110], 
    max_depth         = [None, 2, 5, 6, 7],
    max_features      = ['auto', 'sqrt', 'log2'], 
    min_samples_split = [6, 7, 8],
    min_samples_leaf  = [5, 6, 7]
)

# Criando uma instância da classe do modelo Random Forest.

model = RandomForestClassifier()

# Criando o grid, para fazer a busca dos melhores parâmetros para o modelo.

grid = GridSearchCV(estimator = model, param_grid = paramGrid, cv = 10, verbose = True, n_jobs = -1)

# Buscando pelos melhores parâmetros para o modelo.

grid.fit(trainX, trainY)        

# Exibindo a configuração, do melhor modelo treinado.

print("\n" + "Melhores Parâmetros para o Modelo:" + "\n\n", grid.best_estimator_)
[Parallel(n_jobs=-1)]: Using backend LokyBackend with 16 concurrent workers.
Fitting 10 folds for each of 540 candidates, totalling 5400 fits
[Parallel(n_jobs=-1)]: Done  18 tasks      | elapsed:    0.4s
[Parallel(n_jobs=-1)]: Done 168 tasks      | elapsed:    2.5s
[Parallel(n_jobs=-1)]: Done 418 tasks      | elapsed:    6.0s
[Parallel(n_jobs=-1)]: Done 768 tasks      | elapsed:   10.7s
[Parallel(n_jobs=-1)]: Done 1218 tasks      | elapsed:   16.8s
[Parallel(n_jobs=-1)]: Done 1768 tasks      | elapsed:   23.5s
[Parallel(n_jobs=-1)]: Done 2418 tasks      | elapsed:   31.8s
[Parallel(n_jobs=-1)]: Done 3168 tasks      | elapsed:   41.6s
[Parallel(n_jobs=-1)]: Done 4018 tasks      | elapsed:   52.9s
[Parallel(n_jobs=-1)]: Done 4968 tasks      | elapsed:  1.1min
Melhores Parâmetros para o Modelo:

 RandomForestClassifier(max_depth=5, max_features='log2', min_samples_leaf=5,
                       min_samples_split=7, n_estimators=108)
[Parallel(n_jobs=-1)]: Done 5400 out of 5400 | elapsed:  1.2min finished
In [143]:
# Criando o modelo, com a melhor configuração encontrada.

classifierRF = grid.best_estimator_

# Treinando o modelo com os dados de treino.

classifierRF.fit(X = trainX, y = trainY)
Out[143]:
RandomForestClassifier(max_depth=5, max_features='log2', min_samples_leaf=5,
                       min_samples_split=7, n_estimators=108)
In [144]:
# Calculando a acurácia do modelo para o conjunto de dados de treino.

scoreTrainRF = accuracy_score(trainY, classifierRF.predict(trainX))

# Visualizando o resultado.

print('Acurácia para os dados de treino: ' + str(scoreTrainRF))
Acurácia para os dados de treino: 0.9185667752442996
In [145]:
# Calculando a acurácia do modelo para o conjunto de dados de teste.

scoreTestRF = accuracy_score(testY, classifierRF.predict(testX))

# Visualizando o resultado.

print('Acurácia  para os dados de teste: ' + str(scoreTestRF))
Acurácia  para os dados de teste: 0.8896103896103896
6.3.1.3 Algoritmo Xgboost

Iremos buscar pelos melhores parâmetros, para criar um modelo com algoritmo Xgboost.

In [303]:
# Definindo qual conjunto de dados de treino, já escalado, deve ser utilizado e a sua variável target.

trainX = trainFeaturesNormalized
trainY = trainTarget

# Definindo qual conjunto de dados de teste, já escalado, deve ser utilizado e a sua variável target.

testX = testFeaturesNormalized
testY = testTarget

# Definindo os valores que devem ser testados, em cada um dos parâmetros do modelo especificado.

paramGrid = dict (
    missing          = [np.nan],
    booster          = ['gbtree', 'gblinear', 'dart'],
    max_depth        = [None, 4, 5, 6], 
    n_estimators     = [290, 295, 300, 304, 305], 
    learning_rate    = [0.014, 0.015, 0.016], 
    nthread          = [8], 
    subsample        = [0.93, 0.94, 0.95, 1], 
    colsample_bytree = [0.90, 0.91, 0.92, 0.93, 1], 
    seed             = [100]
)

# Criando uma instância da classe do modelo Random Forest.

model = xgb.XGBClassifier()

# Criando o grid, para fazer a busca dos melhores parâmetros para o modelo.

grid = GridSearchCV(estimator = model, param_grid = paramGrid, cv = 10, verbose = True, n_jobs = -1)

# Buscando pelos melhores parâmetros para o modelo.

grid.fit(trainX, trainY)

# Exibindo a configuração, do melhor modelo treinado.

print("\n" + "Melhores Parâmetros para o Modelo:" + "\n\n", grid.best_estimator_)
Fitting 10 folds for each of 3600 candidates, totalling 36000 fits
[Parallel(n_jobs=-1)]: Using backend LokyBackend with 16 concurrent workers.
[Parallel(n_jobs=-1)]: Done  18 tasks      | elapsed:    1.9s
[Parallel(n_jobs=-1)]: Done 168 tasks      | elapsed:    6.5s
[Parallel(n_jobs=-1)]: Done 418 tasks      | elapsed:   12.0s
[Parallel(n_jobs=-1)]: Done 768 tasks      | elapsed:   21.4s
[Parallel(n_jobs=-1)]: Done 1218 tasks      | elapsed:   32.9s
[Parallel(n_jobs=-1)]: Done 1768 tasks      | elapsed:   48.1s
[Parallel(n_jobs=-1)]: Done 2418 tasks      | elapsed:  1.1min
[Parallel(n_jobs=-1)]: Done 3168 tasks      | elapsed:  1.4min
[Parallel(n_jobs=-1)]: Done 4018 tasks      | elapsed:  1.8min
[Parallel(n_jobs=-1)]: Done 4968 tasks      | elapsed:  2.2min
[Parallel(n_jobs=-1)]: Done 6018 tasks      | elapsed:  2.6min
[Parallel(n_jobs=-1)]: Done 7168 tasks      | elapsed:  3.1min
[Parallel(n_jobs=-1)]: Done 8418 tasks      | elapsed:  3.7min
[Parallel(n_jobs=-1)]: Done 9768 tasks      | elapsed:  4.3min
[Parallel(n_jobs=-1)]: Done 11218 tasks      | elapsed:  4.9min
[Parallel(n_jobs=-1)]: Done 13456 tasks      | elapsed:  5.4min
[Parallel(n_jobs=-1)]: Done 16756 tasks      | elapsed:  5.7min
[Parallel(n_jobs=-1)]: Done 20256 tasks      | elapsed:  6.0min
[Parallel(n_jobs=-1)]: Done 23956 tasks      | elapsed:  6.4min
[Parallel(n_jobs=-1)]: Done 25968 tasks      | elapsed:  9.3min
[Parallel(n_jobs=-1)]: Done 28018 tasks      | elapsed: 12.3min
[Parallel(n_jobs=-1)]: Done 30168 tasks      | elapsed: 15.4min
[Parallel(n_jobs=-1)]: Done 32418 tasks      | elapsed: 18.8min
[Parallel(n_jobs=-1)]: Done 34768 tasks      | elapsed: 22.2min
[Parallel(n_jobs=-1)]: Done 36000 out of 36000 | elapsed: 24.0min finished
Melhores Parâmetros para o Modelo:

 XGBClassifier(base_score=0.5, booster='dart', colsample_bylevel=1,
              colsample_bynode=1, colsample_bytree=0.9, gamma=0, gpu_id=-1,
              importance_type='gain', interaction_constraints='',
              learning_rate=0.015, max_delta_step=0, max_depth=4,
              min_child_weight=1, missing=nan, monotone_constraints='()',
              n_estimators=304, n_jobs=8, nthread=8, num_parallel_tree=1,
              random_state=100, reg_alpha=0, reg_lambda=1, scale_pos_weight=1,
              seed=100, subsample=1, tree_method='exact', validate_parameters=1,
              verbosity=None)
In [304]:
# Criando o modelo, com a melhor configuração encontrada.

classifierXGB = grid.best_estimator_

classifierXGB.fit(X = trainX, y = trainY)
Out[304]:
XGBClassifier(base_score=0.5, booster='dart', colsample_bylevel=1,
              colsample_bynode=1, colsample_bytree=0.9, gamma=0, gpu_id=-1,
              importance_type='gain', interaction_constraints='',
              learning_rate=0.015, max_delta_step=0, max_depth=4,
              min_child_weight=1, missing=nan, monotone_constraints='()',
              n_estimators=304, n_jobs=8, nthread=8, num_parallel_tree=1,
              random_state=100, reg_alpha=0, reg_lambda=1, scale_pos_weight=1,
              seed=100, subsample=1, tree_method='exact', validate_parameters=1,
              verbosity=None)
In [305]:
# Calculando a acurácia do modelo para o conjunto de dados de treino.

scoreTrainXGB = accuracy_score(trainY, classifierXGB.predict(trainX))

# Visualizando o resultado.

print('Acurácia para os dados de treino: ' + str(scoreTrainXGB))
Acurácia para os dados de treino: 0.9657980456026058
In [306]:
# Calculando a acurácia do modelo para o conjunto de dados de teste.

scoreTestXGB = accuracy_score(testY, classifierXGB.predict(testX))

# Visualizando o resultado.

print('Acurácia  para os dados de teste: ' + str(scoreTestXGB))
Acurácia  para os dados de teste: 0.922077922077922

6.3.2 Avaliando as métricas do melhor classificador para os dados de teste

O melhor classificador treinado, utiliza o algoritmo XGBoost com as features normalizadas. Salvaremos as configurações desse modelo em um arquivo .sav.

In [307]:
# Salvando o modelo preditivo especificado.

saveModel(name = 'classifierXGB', model = classifierXGB)
Modelo salvo!

Caso deseje pular as etapas anteriores de treinamento, execute o comando a seguir, para carregar o modelo já treinado.

In [308]:
# Carregando o modelo preditivo especificado.

classifier = loadModel(name = 'classifierXGB')
Modelo carregado!

Para analisar melhor a performance do modelo, precisamos determinar os valores das probabilidades geradas nas previsões.

In [309]:
# Definindo qual conjunto de dados de treino, já escalado, deve ser utilizado e a sua variável target.

trainX = trainFeaturesNormalized
testX  = testFeaturesNormalized

# Realizando as predições das probabilidades, dos dados de treino e teste, para o modelo selecionado.

predTrainProb = classifier.predict_proba(trainX)[:,1]
predTestProb  = classifier.predict_proba(testX)[:,1]

Iremos binarizar as previsões, e os valores a serem previstos, dos conjuntos de dados de treino e teste.

In [310]:
# Definindo as classes positiva e negativa da variável target.

labelPositive = 'Yes'
labelNegative = 'No'

# Criando uma lista com as categorias das classes.

labels = [labelPositive, labelNegative]

# Convertendo dados da variável target, dos dados de treino, para utilizar as labels especificadas.

trainTargetLabels = [labelPositive if t == 1 else labelNegative for t in trainTarget.cat.codes]
trainPredLabels   = [labelPositive if t >= 0.5 else labelNegative for t in predTrainProb]

# Convertendo dados da variável target, dos dados de teste, para utilizar as labels especificadas.

testTargetLabels = [labelPositive if t == 1 else labelNegative for t in testTarget.cat.codes]
testPredLabels   = [labelPositive if t >= 0.5 else labelNegative for t in predTestProb]
In [311]:
# Criando uma Confusion Matrix para avaliar as previsões feitas para os dados de treino.

cm = confusionMatrix(yTrue = trainTargetLabels, yPred = trainPredLabels)

# Exibindo a Confusion Matrix.

cm
Out[311]:
Actual Yes No classError
Predicted
Yes 204 5 0.023923
No 16 389 0.039506
In [312]:
# Criando uma Confusion Matrix para avaliar as previsões feitas para os dados de teste.

cm = confusionMatrix(yTrue = testTargetLabels, yPred = testPredLabels)

# Exibindo a Confusion Matrix.

cm
Out[312]:
Actual Yes No classError
Predicted
Yes 40 4 0.090909
No 8 102 0.072727

Nos dados de teste, constatamos a ocorrência de falsos positivos, mas a proporção de falsos negativos é predominante.

In [313]:
# Plotando a Confusion Matrix dos dados de teste em um gráfico.

plotConfusionMatrix (
    data   = cm.drop(labels= 'classError', axis = 1), 
    labels = labels
)

Vamos calcular algumas estatísticas, baseadas nos resultados gerados pelo modelo, para os dados de teste.

In [314]:
# Calculando os scores de diferentes métricas, com base nas previsões geradas pelo modelo, para os dados de teste.

getClassificationMetrics(yTrue = testTargetLabels, predProb = predTestProb)
Out[314]:
Metrics
Accuracy 0.922078
95% CI for Accuracy (0.8797419257033142, 0.9644139184525299)
Kappa 0.814159
Recall (Sensitivity) 0.833333
Specificity 0.962264
Pos Pred Value 0.909091
Neg Pred Value 0.927273
Precision 0.909091
Avarage Precision 0.809524
Prevalence 0.311688
Detection Rate 0.25974
Detection Prevalence 0.285714
F1 0.869565
ROC AUC 0.962068
Error 0.0779221
95% CI for Error (0.03558608154747015, 0.12025807429668575)
Balanced Accuracy 0.897799
Positive Class Yes

Finalizamos esta análise, concluindo que o algoritmo XGBoost, gerou o modelo com a melhor acurácia. Os scores alcançados para os conjuntos de dados foram:

  • Dados de treino: 0.965798.
  • Dados de teste: 0.922078.

Entre em contato comigo!

Caso tenha alguma dúvida, sugestão ou apenas queira trocar uma ideia sobre este projeto, não hesite em entrar em contato comigo!