EXERCÍCIO ROC CURVE

Exercício ROC curve

Preparando os dados

from gapminder import gapminder

#selecionando somente os dados de 2007
gapminder = gapminder[gapminder['year'] == 2007]

# Cria uma variável booleana para indicar se o país é da Europa
gapminder['is_europe'] = gapminder['continent'] == 'Europe'

gapminder.head()
C:\Users\renat\AppData\Local\Temp\ipykernel_23400\3643757986.py:7: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
  gapminder['is_europe'] = gapminder['continent'] == 'Europe'
country continent year lifeExp pop gdpPercap is_europe
11 Afghanistan Asia 2007 43.828 31889923 974.580338 False
23 Albania Europe 2007 76.423 3600523 5937.029526 True
35 Algeria Africa 2007 72.301 33333216 6223.367465 False
47 Angola Africa 2007 42.731 12420476 4797.231267 False
59 Argentina Americas 2007 75.320 40301927 12779.379640 False

É possível prever se o país é europeu com base nos dados do gapminder?

Treinando o modelo

from sklearn.model_selection import train_test_split

# Selecionar características e alvo
X1 = gapminder[['gdpPercap', 'lifeExp', 'pop']]
y1 = gapminder['is_europe']

# Dividir os dados em conjuntos de treinamento e teste
X1_train, X1_test, y1_train, y1_test = train_test_split(X1, y1, test_size=0.2, random_state=42)

Fazendo a regressão logística

from sklearn.linear_model import LogisticRegression
import numpy as np

# Criar e treinar o modelo de regressão logística
model1 = LogisticRegression()
model1.fit(X1_train, y1_train)

# Coeficientes do modelo
coefficients1 = model1.coef_[0]
intercept1 = model1.intercept_

# Exibir os coeficientes e o intercept
print("Coeficientes:", coefficients1)
print("Intercept:", intercept1)
Coeficientes: [ 1.19708516e-04 -3.96436464e-02 -1.39304800e-08]
Intercept: [-0.00071187]

Odds ratios são exponenciais dos coeficientes e podem ser mais fáceis de interpretar em termos de impacto das variáveis.

Odds Ratios

Os odds ratios (razões de chances) derivam dos coeficientes do modelo de regressão logística e indicam a força e a direção da associação entre cada variável independente (feature) e a variável dependente (a probabilidade do evento ocorrer, neste caso, um país ser europeu).

Um odds ratio:

  • Maior que 1 indica que, à medida que o valor da variável independente aumenta, a probabilidade do evento ocorrer também aumenta. Por exemplo, se um coeficiente tem um odds ratio de 2, isso significa que um aumento de uma unidade nessa variável dobra as chances do evento ocorrer.

  • Igual a 1 sugere que a variável não tem efeito sobre as chances do evento.

  • Menor que 1 indica que, à medida que o valor da variável aumenta, a probabilidade do evento ocorrer diminui. Por exemplo, um odds ratio de 0,5 indica que um aumento de uma unidade na variável reduz pela metade as chances do evento ocorrer.

# Calculando e exibindo Odds Ratios
odds_ratios1 = np.exp(coefficients1)
print("Odds Ratios:", odds_ratios1)
Odds Ratios: [1.00011972 0.96113188 0.99999999]
  1. 1.00011972 (gdpPercap): Este odds ratio está muito próximo de 1, o que sugere que um aumento no PIB per capita tem um efeito muito pequeno, mas positivo, sobre a probabilidade de um país ser europeu. Mais especificamente, um aumento de uma unidade no PIB per capita (suponha que a unidade seja 1 dólar, por exemplo) aumenta ligeiramente as chances de o país ser europeu. O efeito é, no entanto, quase insignificante devido à proximidade do valor com 1.

  2. 0.96113188 (lifeExp): Este odds ratio é menor que 1, o que indica que há uma relação inversa entre a expectativa de vida e a probabilidade de um país ser europeu. Em termos práticos, para cada aumento de uma unidade na expectativa de vida (suponha que a unidade seja um ano), as chances de o país ser europeu diminuem em aproximadamente 3.9% (100 - 96.113188%). Isto pode ser contraintuitivo e poderia requerer uma investigação mais aprofundada para entender as nuances ou possíveis confusões de variáveis.

  3. 0.99999999 (pop): Este valor, estando extremamente próximo de 1, sugere que mudanças na população têm um efeito praticamente nulo sobre a probabilidade de um país ser europeu. A mudança é tão pequena que é praticamente indistinguível de nenhum efeito.

O relatório de classificação fornece uma visão detalhada do desempenho do modelo, incluindo precisão, recall, F1-score e suporte para cada classe.

Relatório de Classificação

O relatório de classificação fornece várias métricas que ajudam a avaliar o desempenho do seu modelo em diferentes aspectos:

  1. Precisão (Precision): A precisão é a proporção de identificações positivas que foram corretas. Por exemplo, se o modelo prevê que 10 países são europeus e 7 realmente são, a precisão é 70%.

  2. Recall (Sensibilidade ou Taxa de Verdadeiros Positivos): Recall é a proporção de positivos reais que foram identificados corretamente. Por exemplo, se existem 10 países europeus reais no conjunto de teste e o modelo identificou corretamente 7 deles, o recall é 70%.

  3. F1-Score: Esta é a média harmônica da precisão e do recall. O F1-Score é uma forma de combinar tanto a precisão quanto o recall em uma única métrica que captura ambos os aspectos do desempenho do modelo. É particularmente útil se a distribuição das classes for desigual. Um F1-Score alto sugere um bom equilíbrio entre precisão e recall.

  4. Suporte (Support): O suporte é o número de ocorrências de cada classe no conjunto de dados. Por exemplo, se há 20 países europeus no conjunto de teste, o suporte para a classe ‘Europa’ é 20.

  5. Acurácia (Accuracy): Acurácia é a proporção de previsões corretas (tanto verdadeiros positivos quanto verdadeiros negativos) entre o total de casos examinados.

Essas métricas são apresentadas para cada classe (neste caso, países europeus e não europeus), bem como uma média que pode ser ponderada baseada no suporte de cada classe.

from sklearn.metrics import classification_report

# Previsões no conjunto de teste
y1_pred = model1.predict(X1_test)

# Gerar o relatório de classificação
report1 = classification_report(y1_test, y1_pred)
print("Relatório de Classificação:\n", report1)
Relatório de Classificação:
               precision    recall  f1-score   support

       False       0.78      0.95      0.86        22
        True       0.50      0.14      0.22         7

    accuracy                           0.76        29
   macro avg       0.64      0.55      0.54        29
weighted avg       0.71      0.76      0.70        29
  1. Precisão (Precision):

    • False (0.78): Quando o modelo prediz que um país não é europeu, ele está correto 78% das vezes.

    • True (0.50): Quando o modelo prediz que um país é europeu, ele está correto 50% das vezes.

  2. Recall:

    • False (0.95): Dos países que realmente não são europeus, o modelo consegue identificar 95% deles corretamente.

    • True (0.14): Dos países que realmente são europeus, o modelo só identifica corretamente 14% deles.

  3. F1-Score:

    • False (0.86): Este é o equilíbrio entre precisão e recall para países não europeus, indicando uma boa performance do modelo para esta classe.

    • True (0.22): Este valor é bastante baixo para a classe europeia, sugerindo que o modelo tem dificuldades em equilibrar precisão e recall para identificar países europeus corretamente.

Métricas Gerais

  • Accuracy (Acurácia) (0.76): No geral, o modelo está correto em 76% das vezes, independentemente da classe.

  • Macro Average:

    • Precisão (0.64): Média das precisões para ambas as classes.

    • Recall (0.55): Média dos recalls para ambas as classes.

    • F1-Score (0.54): Média dos F1-scores para ambas as classes.

  • Weighted Average:

    • Precisão (0.71): Média das precisões, ponderada pelo suporte (número de casos) de cada classe.

    • Recall (0.76): Média dos recalls, ponderada pelo suporte de cada classe.

    • F1-Score (0.70): Média dos F1-scores, ponderada pelo suporte de cada classe.

Interpretação

  • O modelo tem um bom desempenho para identificar países que não são europeus, com alta precisão e recall para essa classe.

  • No entanto, para países que são europeus, o modelo tem dificuldades, como evidenciado pela baixa precisão, recall e F1-score. Isso indica que o modelo pode estar tendencioso para a classe mais comum (não europeu), possivelmente devido a um desbalanceamento nas quantidades de dados de treinamento para cada classe.

  • A acurácia geral é relativamente alta, mas isso pode ser enganoso devido ao desequilíbrio nas classes. O modelo é eficaz em prever a classe majoritária, mas não tão bom em identificar a classe minoritária.

Ações Recomendadas

  • Rebalancear os Dados: Considerar métodos para balancear as classes, como oversampling da classe minoritária ou undersampling da classe majoritária.

  • Ajustar o Modelo: Experimentar com ajustes nos parâmetros do modelo ou tentar outros algoritmos de classificação que possam lidar melhor com classes desbalanceadas.

  • Analisar Variáveis: Revisar as variáveis usadas para treinamento para garantir que estão proporcionando informações suficientes para distinguir entre as classes.

Curva ROC

from sklearn.metrics import roc_curve, auc
import matplotlib.pyplot as plt

# Prever probabilidades para o conjunto de teste
y1_scores = model1.predict_proba(X1_test)[:, 1]

# Calcular a curva ROC
fpr1, tpr1, thresholds = roc_curve(y1_test, y1_scores)
roc_auc1 = auc(fpr1, tpr1)

# Plotar a curva ROC
plt.figure()
plt.plot(fpr1, tpr1, color='darkorange', lw=2, label='ROC curve (area = %0.2f)' % roc_auc1)
plt.plot([0, 1], [0, 1], color='navy', lw=2, linestyle='--')
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('ROC Curve')
plt.legend(loc="lower right")
plt.show()

  • 0.71: Um AUC de 0.71 sugere que o modelo tem uma boa capacidade de discriminação. Especificamente, isso significa que se você escolher aleatoriamente um exemplo positivo e um exemplo negativo, há uma probabilidade de 71% de que o modelo classifique corretamente o exemplo positivo com uma pontuação maior do que o exemplo negativo.

Isso ocorre porquanto

  • Existem países com GDP per Capita alto fora da europa, fazendo com que diminua a dependência (não sei se o termo correto é dependência);

  • Não há correlação entre população e a variável alvo.

  • A única variável que parece relavante é a expectativa de vida.

Contudo esse modelo usando as 3 variáveis é relativamente impreciso. Vamos testar as 3 variáveis separadamente para ver qual pode ser mais eficaz.

Somente EXPECTATIVA DE VIDA.

# Preparando os dados
Xexp = gapminder[['lifeExp']]  # Usando apenas 'lifeExp' como variável
yexp = gapminder['is_europe']

# Dividindo os dados em conjuntos de treinamento e teste
Xexp_train, Xexp_test, yexp_train, yexp_test = train_test_split(Xexp, yexp, test_size=0.2, random_state=42)

# Criando e treinando o modelo de regressão logística
modelexp = LogisticRegression()
modelexp.fit(Xexp_train, yexp_train)

# Exibindo o coeficiente e o intercept
print("Coeficiente:", modelexp.coef_)
print("Intercept:", modelexp.intercept_)

# Calculando o odds ratio
odds_ratioexp = np.exp(modelexp.coef_)
print("Odds Ratio:", odds_ratioexp)
Coeficiente: [[0.3077291]]
Intercept: [-24.14574486]
Odds Ratio: [[1.36033242]]
from sklearn.metrics import classification_report

# Previsões no conjunto de teste
yexp_pred = modelexp.predict(Xexp_test)

# Gerar o relatório de classificação
reportexp = classification_report(yexp_test, yexp_pred)
print("Relatório de Classificação:\n", reportexp)
Relatório de Classificação:
               precision    recall  f1-score   support

       False       0.83      0.91      0.87        22
        True       0.60      0.43      0.50         7

    accuracy                           0.79        29
   macro avg       0.72      0.67      0.68        29
weighted avg       0.78      0.79      0.78        29

Somente GDP PER CAP

# Preparando os dados
Xgdp = gapminder[['gdpPercap']]  # Usando apenas 'gdpPercap' como variável
ygdp = gapminder['is_europe']

# Dividindo os dados em conjuntos de treinamento e teste
Xgdp_train, Xgdp_test, ygdp_train, ygdp_test = train_test_split(Xgdp, ygdp, test_size=0.2, random_state=42)

# Criando e treinando o modelo de regressão logística
modelgdp = LogisticRegression()
modelgdp.fit(Xgdp_train, ygdp_train)

# Exibindo o coeficiente e o intercept
print("Coeficiente:", modelgdp.coef_)
print("Intercept:", modelgdp.intercept_)

# Calculando o odds ratio
odds_ratiogdp = np.exp(modelgdp.coef_)
print("Odds Ratio:", odds_ratiogdp)
Coeficiente: [[0.00010083]]
Intercept: [-2.94203798]
Odds Ratio: [[1.00010084]]

Somente População

# Preparando os dados
Xpop = gapminder[['pop']]  # Usando apenas 'pop' como variável
ypop = gapminder['is_europe']

# Dividindo os dados em conjuntos de treinamento e teste
Xpop_train, Xpop_test, ypop_train, ypop_test = train_test_split(Xpop, ypop, test_size=0.2, random_state=42)

# Criando e treinando o modelo de regressão logística
modelpop = LogisticRegression()
modelpop.fit(Xpop_train, ypop_train)

# Exibindo o coeficiente e o intercept
print("Coeficiente:", modelpop.coef_)
print("Intercept:", modelpop.intercept_)

# Calculando o odds ratio
odds_ratiopop = np.exp(modelpop.coef_)
print("Odds Ratio:", odds_ratiopop)
Coeficiente: [[-4.01699717e-08]]
Intercept: [-1.31775716e-14]
Odds Ratio: [[0.99999996]]

Somente Expectativa de Vida e GDP per Capita

# Preparando os dados
Xgdpexp = gapminder[['gdpPercap', 'lifeExp']]  # Usando apenas 'gdppercap e life expc' como variável
ygdpexp = gapminder['is_europe']

# Dividindo os dados em conjuntos de treinamento e teste
Xgdpexp_train, Xgdpexp_test, ygdpexp_train, ygdpexp_test = train_test_split(Xgdpexp, ygdpexp, test_size=0.2, random_state=42)

# Criando e treinando o modelo de regressão logística
modelgdpexp = LogisticRegression()
modelgdpexp.fit(Xgdpexp_train, ygdpexp_train)

# Exibindo o coeficiente e o intercept
print("Coeficiente:", modelgdpexp.coef_)
print("Intercept:", modelgdpexp.intercept_)

# Calculando o odds ratio
odds_ratiogdpexp = np.exp(modelgdpexp.coef_)
print("Odds Ratio:", odds_ratiogdpexp)
Coeficiente: [[2.86345410e-05 2.29362096e-01]]
Intercept: [-18.74252593]
Odds Ratio: [[1.00002863 1.2577974 ]]
from sklearn.metrics import classification_report

# Previsões no conjunto de teste
ygdpexp_pred = modelgdpexp.predict(Xgdpexp_test)

# Gerar o relatório de classificação
reportgdpexp = classification_report(ygdpexp_test, ygdpexp_pred)
print("Relatório de Classificação:\n", reportgdpexp)
Relatório de Classificação:
               precision    recall  f1-score   support

       False       0.83      0.91      0.87        22
        True       0.60      0.43      0.50         7

    accuracy                           0.79        29
   macro avg       0.72      0.67      0.68        29
weighted avg       0.78      0.79      0.78        29

Ao analisar os dados, percebe-se que a expectativa de vida isolada é a melhor variável para o nosso modelo.

Curva de ROC somente com Expectativa de vida.

# Prever probabilidades para o conjunto de teste
yexp_scores = modelexp.predict_proba(Xexp_test)[:, 1]

# Calcular a curva ROC
fprexp, tprexp, thresholds = roc_curve(yexp_test, yexp_scores)
roc_aucexp = auc(fprexp, tprexp)

# Plotar a curva ROC
plt.figure()
plt.plot(fprexp, tprexp, color='darkorange', lw=2, label='ROC curve (area = %0.2f)' % roc_aucexp)
plt.plot([0, 1], [0, 1], color='navy', lw=2, linestyle='--')
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('ROC Curve')
plt.legend(loc="lower right")
plt.show()

Uma AUC de 0.81 é uma indicação de que o modelo é eficaz e tem uma capacidade robusta de discriminação, mas com espaço para melhoria.