import numpy as np
import pandas as pd
123)
np.random.seed(
= 100
n = pd.DataFrame({
data 'true': ['chien'] * 50 + ['chat'] * 50,
'probs': np.concatenate([
0.5, 1, 50),
np.random.uniform(0, 0.5, 50)
np.random.uniform(
])
})
'pred'] = data['probs'].apply(lambda x: 'chien' if x > 0.5 else 'chat')
data[
= np.random.choice(n, 15, replace=False)
indices_erreurs 'probs'] = 1 - data.loc[indices_erreurs, 'probs']
data.loc[indices_erreurs, 'pred'] = data.loc[indices_erreurs, 'pred'].map({'chien': 'chat', 'chat': 'chien'}) data.loc[indices_erreurs,
Exemple de données
Nous cherchons à identifier les résultats d’un modèle qui cherche à différencier des prédictions de chiens et de chats. Pour évaluer leur performance, des métriques adaptées permettent de mesurer à quel point un modèle est précis, fiable et équilibré dans ses prédictions.
set.seed(123)
<- 100
n <- data.frame(
data true = factor(c(rep("chien", 50), rep("chat", 50))),
probs = c(runif(50, 0.5, 1), runif(50, 0, 0.5))
)
$pred <- factor(ifelse(data$probs > 0.5, "chien", "chat"))
data
<- sample(1:n, 15)
indices_erreurs $probs[indices_erreurs] <- 1 - data$probs[indices_erreurs]
data$pred[indices_erreurs] <- ifelse(data$pred[indices_erreurs] == "chien", "chat", "chien") data
Metriques
Matrice de confusion
La matrice de confusion est une représentation en tableau des prédictions correctes et incorrectes :
\[ \begin{bmatrix} TP & FP \\ FN & TN \end{bmatrix} \]
- TP (True Positives) : Nombre de prédictions correctes pour la classe positive.
- FP (False Positives) : Nombre de prédictions incorrectes pour la classe positive.
- FN (False Negatives) : Nombre de prédictions incorrectes pour la classe négative.
- TN (True Negatives) : Nombre de prédictions correctes pour la classe négative.
from sklearn.metrics import confusion_matrix
import seaborn as sns
import matplotlib.pyplot as plt
= confusion_matrix(data['true'], data['pred'])
conf_matrix print("Matrice de confusion Python:")
Matrice de confusion Python:
print(conf_matrix)
[[42 8]
[ 7 43]]
=(6, 4))
plt.figure(figsize
sns.heatmap(conf_matrix, =True,
annot='d',
fmt=['chat', 'chien'],
xticklabels=['chat', 'chien'])
yticklabels'Matrice de confusion (Python)')
plt.title('Valeur réelle')
plt.xlabel('Prédiction')
plt.ylabel( plt.show()
library(ggplot2)
print("Matrice de confusion R:")
[1] "Matrice de confusion R:"
table(Prédit = data$pred, Réel = data$true)
Réel
Prédit chat chien
chat 44 9
chien 6 41
<- as.data.frame(table(data$pred, data$true))
conf_matrix_r names(conf_matrix_r) <- c("Prediction", "Real", "Count")
ggplot(conf_matrix_r,
aes(x = Real, y = Prediction, fill = Count)) +
geom_tile() +
geom_text(aes(label = Count)) +
scale_fill_gradient(low = "white", high = "steelblue") +
theme_minimal() +
labs(title = "Matrice de confusion (R)")
Accuracy
L’Accuracy mesure la proportion de prédictions correctes parmi l’ensemble des prédictions.
\[ \text{Accuracy} = \frac{\text{Vrai Positifs} + \text{Vrai Négatifs}}{\text{Total}} \]
Avantages : Facile à comprendre et à interpréter. Représente bien la performance globale d’un modèle lorsque les classes sont équilibrées.
Inconvénients : Ne prend pas en compte le déséquilibre des classes. Un modèle peut avoir une haute accuracy même s’il classe mal les classes minoritaires.
from sklearn.metrics import accuracy_score
= accuracy_score(data['true'], data['pred'])
acc_sklearn print(f"Accuracy (sklearn): {acc_sklearn:.3f}")
Accuracy (sklearn): 0.850
<- mean(data$pred == data$true)
acc_simple print(paste("Accuracy (simple):", round(acc_simple, 3)))
[1] "Accuracy (simple): 0.85"
Précision
La précision est la proportion des prédictions positives correctes parmi toutes les prédictions positives.
Avantages : Utile lorsque l’on veut minimiser les faux positifs. Par exemple, dans des scénarios où une fausse alerte coûte cher (par exemple, détection de fraude).
Inconvénients : Ne prend pas en compte les faux négatifs, ce qui peut être problématique dans certains cas, par exemple, lorsque l’on souhaite éviter les faux négatifs.
\[ \text{Précision} = \frac{\text{Vrai Positifs}}{\text{Vrai Positifs} + \text{Faux Positifs}} \]
from sklearn.metrics import precision_score
= precision_score(
precision_per_class 'true'],
data['pred'],
data[=None,
average=['chat', 'chien']
labels
)print("Précision par classe (sklearn):")
Précision par classe (sklearn):
print(f"Chat: {precision_per_class[0]:.3f}")
Chat: 0.857
print(f"Chien: {precision_per_class[1]:.3f}")
Chien: 0.843
# Précision moyenne
= precision_score(
precision_avg 'true'],
data['pred'],
data[='macro'
average
)print(f"Précision moyenne: {precision_avg:.3f}")
Précision moyenne: 0.850
<- table(Prédit = data$pred, Réel = data$true)
conf_matrix <- conf_matrix["chat","chat"] / sum(conf_matrix[,"chat"])
precision_chat <- conf_matrix["chien","chien"] / sum(conf_matrix[,"chien"])
precision_chien
print("\nPrécision par classe (manuel):")
[1] "\nPrécision par classe (manuel):"
print(paste("Chat:", round(precision_chat, 3)))
[1] "Chat: 0.88"
print(paste("Chien:", round(precision_chien, 3)))
[1] "Chien: 0.82"
<- mean(c(precision_chat, precision_chien))
precision_moy print(paste("Précision moyenne:", round(precision_moy, 3)))
[1] "Précision moyenne: 0.85"
Recall
Le Recall mesure la proportion des vrais positifs détectés parmi tous les réels positifs. Il est particulièrement important lorsqu’on veut minimiser les faux négatifs.
Avantages : Utile dans des contextes où il est crucial de capturer autant de cas positifs que possible (par exemple, dans les tests médicaux).
Inconvénients : Ignore les faux positifs, ce qui peut mener à une hausse des faux positifs dans certains cas.
\[ \text{Recall} = \frac{\text{Vrai Positifs}}{\text{Vrai Positifs} + \text{Faux Négatifs}} \]
from sklearn.metrics import recall_score
= recall_score(
recall_per_class 'true'],
data['pred'],
data[=None,
average=['chat', 'chien']
labels
)print("Recall par classe (sklearn):")
Recall par classe (sklearn):
print(f"Chat: {recall_per_class[0]:.3f}")
Chat: 0.840
print(f"Chien: {recall_per_class[1]:.3f}")
Chien: 0.860
# Recall moyen
= recall_score(
recall_avg 'true'],
data['pred'],
data[='macro'
average
)print(f"Recall moyen: {recall_avg:.3f}")
Recall moyen: 0.850
<- table(Prédit = data$pred, Réel = data$true)
conf_matrix <- conf_matrix["chat","chat"] / sum(conf_matrix["chat",])
recall_chat <- conf_matrix["chien","chien"] / sum(conf_matrix["chien",])
recall_chien
print("\nRecall par classe (manuel):")
[1] "\nRecall par classe (manuel):"
print(paste("Chat:", round(recall_chat, 3)))
[1] "Chat: 0.83"
print(paste("Chien:", round(recall_chien, 3)))
[1] "Chien: 0.872"
# Recall moyen
<- mean(c(recall_chat, recall_chien))
recall_moy print(paste("Recall moyen:", round(recall_moy, 3)))
[1] "Recall moyen: 0.851"
F1-Score
Le F1-Score est la moyenne harmonique entre la précision et le recall, offrant ainsi un compromis entre les deux. C’est une mesure utile quand il faut équilibrer la précision et le recall
Avantages : Prend en compte à la fois les faux positifs et les faux négatifs. Utile pour les problèmes avec des classes déséquilibrées.
Inconvénients : Si l’un des deux (précision ou recall) est faible, l’F1-score sera également faible.
\[ \text{F1-Score} = 2 \times\frac{\text{Précision} \times \text{Recall}}{\text{Précision} + \text{Recall}} \]
from sklearn.metrics import f1_score
# F1-score par classe
= f1_score(
f1_per_class 'true'],
data['pred'],
data[=None,
average=['chat', 'chien']
labels
)print("F1-Score par classe (sklearn):")
F1-Score par classe (sklearn):
print(f"Chat: {f1_per_class[0]:.3f}")
Chat: 0.848
print(f"Chien: {f1_per_class[1]:.3f}")
Chien: 0.851
# F1-score moyen
= f1_score(
f1_avg 'true'],
data['pred'],
data[='macro'
average
)print(f"F1-Score moyen: {f1_avg:.3f}")
F1-Score moyen: 0.850
<- conf_matrix["chat", "chat"] / sum(conf_matrix[, "chat"])
precision_chat <- conf_matrix["chat", "chat"] / sum(conf_matrix["chat", ])
recall_chat <- 2 * (precision_chat * recall_chat) / (precision_chat + recall_chat)
f1_chat
<- conf_matrix["chien", "chien"] / sum(conf_matrix[, "chien"])
precision_chien <- conf_matrix["chien", "chien"] / sum(conf_matrix["chien", ])
recall_chien <- 2 * (precision_chien * recall_chien) / (precision_chien + recall_chien)
f1_chien
print("\nF1-Score par classe (manuel):")
[1] "\nF1-Score par classe (manuel):"
print(paste("Chat:", round(f1_chat, 3)))
[1] "Chat: 0.854"
print(paste("Chien:", round(f1_chien, 3)))
[1] "Chien: 0.845"
# F1-score moyen
<- mean(c(f1_chat, f1_chien))
f1_moy print(paste("F1-Score moyen:", round(f1_moy, 3)))
[1] "F1-Score moyen: 0.85"
ROC-AUC (Area Under the Curve)
La courbe ROC est utilisée pour visualiser la performance d’un modèle en fonction de ses seuils de classification. L’AUC mesure la capacité du modèle à distinguer entre les classes.
Avantages : Fonctionne bien avec des classes déséquilibrées et permet une comparaison entre modèles avec des seuils différents.
Inconvénients : Peut être difficile à interpréter dans des contextes très spécifiques.
\[ AUC = \int_0^1 \text{TPR}(fpr) \, dfpr \]
from sklearn.metrics import roc_auc_score, roc_curve
= roc_auc_score(data['true'] == 'chien', data['probs'])
roc_auc print(f"ROC-AUC: {roc_auc:.3f}")
ROC-AUC: 0.841
= roc_curve(data['true'] == 'chien', data['probs'])
fpr, tpr, thresholds
=(8, 6))
plt.figure(figsize='blue', label=f'ROC curve (AUC = {roc_auc:.2f})')
plt.plot(fpr, tpr, color0, 1], [0, 1], color='gray', linestyle='--')
plt.plot(['Taux de Faux Positifs (FPR)')
plt.xlabel('Taux de Vrais Positifs (TPR)')
plt.ylabel('Courbe ROC')
plt.title(='lower right')
plt.legend(loc plt.show()
library(pROC)
Type 'citation("pROC")' for a citation.
Attaching package: 'pROC'
The following objects are masked from 'package:stats':
cov, smooth, var
<- roc(data$true == "chien", data$probs)$auc roc_auc
Setting levels: control = FALSE, case = TRUE
Setting direction: controls < cases
print(sprintf("ROC-AUC: %.3f\n", roc_auc))
[1] "ROC-AUC: 0.856\n"
<- roc(data$true == "chien", data$probs) roc_curve
Setting levels: control = FALSE, case = TRUE
Setting direction: controls < cases
plot(roc_curve, main = "Courbe ROC", col = "blue")
legend("bottomright", legend = paste("AUC =", round(roc_auc, 2)), col = "blue", lty = 1)
Log Loss (Logarithmic Loss)
Le Log-Loss mesure la performance d’un modèle en termes de probabilité. Plus il est bas, meilleure est la qualité des probabilités assignées par le modèle.
Avantages : Prend en compte la confiance du modèle dans ses prédictions, ce qui est important pour évaluer les modèles qui prédisent des probabilités.
Inconvénients : Sensible aux prédictions incorrectes avec une forte confiance.
\[ \text{Log Loss} = - \frac{1}{N} \sum_{i=1}^{N} \left[ y_i \log(p_i) + (1 - y_i) \log(1 - p_i) \right] \]
from sklearn.metrics import log_loss
= log_loss(data['true'], np.vstack([1 - data['probs'], data['probs']]).T, labels=['chat', 'chien'])
log_loss_value print(f"Log-Loss: {log_loss_value:.3f}")
Log-Loss: 0.520
$true_binary <- ifelse(data$true == "chien", 1, 0)
data
<- -mean(data$true_binary * log(data$probs) + (1 - data$true_binary) * log(1 - data$probs))
log_loss
print(paste("Log Loss: ", round(log_loss, 4)))
[1] "Log Loss: 0.4953"
Matthews Correlation Coefficient (MCC)
Le MCC mesure la corrélation entre les prédictions et les résultats réels, en prenant en compte les vrais positifs, faux positifs, vrais négatifs et faux négatifs. C’est une métrique particulièrement utile pour les classes déséquilibrées.
Avantages : Représente un bon compromis global entre toutes les erreurs possibles (faux positifs, faux négatifs, vrais positifs, vrais négatifs).
Inconvénients : Plus difficile à interpréter que d’autres métriques comme l’accuracy ou le F1-score.
\[ MCC = \frac{TP \times TN - FP \times FN}{\sqrt{(TP + FP)(TP + FN)(TN + FP)(TN + FN)}} \]
from sklearn.metrics import matthews_corrcoef
= matthews_corrcoef(data['true'], data['pred'])
mcc_value print(f"Matthews Correlation Coefficient (MCC): {mcc_value:.3f}")
Matthews Correlation Coefficient (MCC): 0.700
library(mltools)
<- mcc(data$pred, data$true)
mcc_value print(sprintf("Matthews Correlation Coefficient (MCC): %.3f\n", mcc_value))
[1] "Matthews Correlation Coefficient (MCC): 0.701\n"