Frontière de décision et comparaison à une baseline
Prédire une classe, pas une probabilité
Section titled “Prédire une classe, pas une probabilité”Le modèle produit une probabilité continue ; pour obtenir une décision (« normal » ou « à risque »), il faut appliquer un seuil — 0,5 par défaut :
def predict(X, theta, threshold=0.5): return (model(X, theta) >= threshold).astype(int)
pred_train = predict(X_train, theta_final)pred_test = predict(X_test, theta_final)
print("Accuracy train:", np.mean(y_train == pred_train))print("Accuracy test:", np.mean(y_test == pred_test))Accuracy train: 1.0Accuracy test: 1.0Comparer à une baseline
Section titled “Comparer à une baseline”Une accuracy de 100 % est-elle vraiment impressionnante ? Cela dépend entièrement de la difficulté du problème — d’où le réflexe du module 1 : comparer à une baseline naïve.
classe_majoritaire = int(round(y_train.mean()))baseline_pred = np.full_like(y_test, classe_majoritaire)print("Accuracy baseline (classe majoritaire):", np.mean(y_test == baseline_pred))Accuracy baseline (classe majoritaire): 0.475Une baseline qui prédit toujours la classe majoritaire n’obtient que 47,5 % ici (les classes sont presque équilibrées, donc « toujours prédire la même chose » n’apporte quasiment rien) : la performance du modèle (100 %) n’est donc pas un artefact du déséquilibre des classes, mais reflète une réelle séparation entre les deux groupes.
Visualiser la frontière de décision
Section titled “Visualiser la frontière de décision”Avec seulement deux features, on peut visualiser exactement où le modèle place la frontière entre les deux classes : on génère une grille de points couvrant tout le plan, on prédit la classe de chaque point de la grille, puis on colore le fond en conséquence.
import matplotlib.pyplot as plt
x_min, x_max = X_train[:, 0].min() - 1, X_train[:, 0].max() + 1y_min, y_max = X_train[:, 1].min() - 1, X_train[:, 1].max() + 1xx, yy = np.meshgrid(np.linspace(x_min, x_max, 200), np.linspace(y_min, y_max, 200))
grille = make_design_matrix(xx.ravel(), yy.ravel())Z = predict(grille, theta_final).reshape(xx.shape)
fig, ax = plt.subplots()ax.contourf(xx, yy, Z, alpha=0.3, cmap="RdBu")ax.scatter(X_train[:, 0], X_train[:, 1], c=y_train.ravel(), cmap="RdBu", edgecolor="k")ax.set_xlabel("Débit (standardisé)")ax.set_ylabel("Latence (standardisée)")ax.set_title("Frontière de décision — BoundaryScope")plt.savefig("frontiere_decision.png")Le motif meshgrid → ravel → predict → reshape → contourf est un idiome standard, indépendant de l’algorithme utilisé : on le retrouvera à l’identique pour n’importe quel classifieur scikit-learn dans les modules suivants (le module 4, en particulier, l’utilise pour évaluer un classifieur bien plus complexe).
Prochaine étape
Section titled “Prochaine étape”👉 Synthèse : from scratch face à scikit-learn
Junior TSAFACK – 12/09/2026