import math
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.model_selection import KFold
from matplotlib.colors import ListedColormap
Objectifs :¶
Programmer quelques méthodes de classification statistique vues en cours (estimation de gaussiennes, séparation linéaire, kppv, Parzen), évaluer leur performance sur des jeux de données test, comparer les méthodes, ...
Données de travail¶
On dispose pour 3 problèmes de classification à 5 classes {1,2,3,4,5} dans R2 de 100 échantillons par classe pour l'apprentissage (data_tp{1,2,3}.app) et 100 échantillons par classe pour le test (data_tp{1,2,3}.dec) des classifieurs. On peut visualiser la répartition de ces échantillons (data_tp{1,2,3}_{app,dec}.gif).
data = {}
# Définir la taille de la figure
plt.figure(figsize=(12, 10))
for i in [1, 2, 3]:
data['X_trainTp{}'.format(i)] = np.loadtxt('data/data_tp{}_app.txt'.format(i), usecols=(1, 2))
data['y_trainTp{}'.format(i)] = np.loadtxt('data/data_tp{}_app.txt'.format(i), usecols=0, dtype=int)
data['X_testTp{}'.format(i)] = np.loadtxt('data/data_tp{}_dec.txt'.format(i), usecols=(1, 2))
data['y_testTp{}'.format(i)] = np.loadtxt('data/data_tp{}_dec.txt'.format(i), usecols=0, dtype=int)
# Plot training data
plt.subplot(3, 2, 2 * i - 1)
plt.scatter(data['X_trainTp{}'.format(i)][:, 0], data['X_trainTp{}'.format(i)][:, 1],
c=data['y_trainTp{}'.format(i)], marker='o', label='Training Data - Problem {}'.format(i))
plt.title('Distribution des échantillons d\'apprentissage - Problème {}'.format(i))
plt.xlabel('X')
plt.ylabel('Y')
plt.legend()
# Plot test data
plt.subplot(3, 2, 2 * i)
plt.scatter(data['X_testTp{}'.format(i)][:, 0], data['X_testTp{}'.format(i)][:, 1],
c=data['y_testTp{}'.format(i)], marker='x', label='Test Data - Problem {}'.format(i))
plt.title('Distribution des échantillons de test - Problème {}'.format(i))
plt.xlabel('X')
plt.ylabel('Y')
plt.legend()
plt.tight_layout()
plt.show()
Estimation de gaussiennes:¶
Programmer un classifieur par distance euclidienne minimum. Le tester sur les 3 jeux de données:¶
class EuclideanClassifier:
def __init__(self):
self.X_train = None
self.y_train = None
def fit(self, X_train, y_train):
self.X_train = X_train
self.y_train = y_train
def predict(self, X_test):
predictions = []
for x in X_test:
distances = np.linalg.norm(self.X_train - x, axis=1)
nearest_neighbor_index = np.argmin(distances)
predictions.append(self.y_train[nearest_neighbor_index])
return np.array(predictions)
# Utilisation du classifieur sur les données
classifier = EuclideanClassifier()
for i in [1, 2, 3]:
X_train = data['X_trainTp{}'.format(i)]
y_train = data['y_trainTp{}'.format(i)]
X_test = data['X_testTp{}'.format(i)]
# Entraîner le classifieur
classifier.fit(X_train, y_train)
# Prédire les classes pour les données de test
predictions = classifier.predict(X_test)
# Évaluer la performance (vous pouvez ajouter une évaluation plus détaillée si nécessaire)
accuracy = np.mean(predictions == data['y_testTp{}'.format(i)])
print(f"Accuracy for Problem {i}: {accuracy * 100} %")
Accuracy for Problem 1: 99.2 % Accuracy for Problem 2: 92.0 % Accuracy for Problem 3: 64.60000000000001 %
Evaluer ses performances (taux de bonne classificationen Top1 et Top2, matrice de confusion)¶
def calculate_accuracy_top1(y_true, y_pred):
correct_predictions = np.sum(y_true == y_pred)
total_samples = len(y_true)
accuracy_top1 = correct_predictions / total_samples
return accuracy_top1
def calculate_accuracy_top2(X_train, X_test, y_test):
top2_predictions = np.argsort(X_train @ X_test.T, axis=0)[-2:]
correct_top2_predictions = np.sum(top2_predictions == y_test, axis=0)
accuracy_top2 = np.mean(correct_top2_predictions > 0)
return accuracy_top2
def calculate_confusion_matrix(y_true, y_pred, num_classes):
confusion_mat = np.zeros((num_classes, num_classes), dtype=int)
for true_label, pred_label in zip(y_true, y_pred):
confusion_mat[true_label - 1, pred_label - 1] += 1
return confusion_mat
# Utilisation du classifieur sur les données
classifier = EuclideanClassifier()
for i in [1, 2, 3]:
X_train = data['X_trainTp{}'.format(i)]
y_train = data['y_trainTp{}'.format(i)]
X_test = data['X_testTp{}'.format(i)]
y_test = data['y_testTp{}'.format(i)]
# Entraîner le classifieur
classifier.fit(X_train, y_train)
# Prédire les classes pour les données de test
predictions = classifier.predict(X_test)
# Calculer le taux de bonne classification en Top1
accuracy_top1 = calculate_accuracy_top1(y_test, predictions)
# Calculer le taux de bonne classification en Top2
accuracy_top2 = calculate_accuracy_top2(X_train, X_test, y_test)
# Calculer la matrice de confusion
confusion_mat = calculate_confusion_matrix(y_test, predictions, num_classes=5)
print(f"Performance for Problem {i}:")
print(f"Top-1 Accuracy: {accuracy_top1}")
print(f"Top-2 Accuracy: {accuracy_top2}")
print("Confusion Matrix:")
print(confusion_mat)
print("="*30)
Performance for Problem 1: Top-1 Accuracy: 0.992 Top-2 Accuracy: 0.018 Confusion Matrix: [[ 99 0 0 0 1] [ 0 99 0 0 1] [ 0 0 100 0 0] [ 0 0 0 100 0] [ 0 0 1 1 98]] ============================== Performance for Problem 2: Top-1 Accuracy: 0.92 Top-2 Accuracy: 0.0 Confusion Matrix: [[100 0 0 0 0] [ 0 89 11 0 0] [ 2 4 83 2 9] [ 0 0 3 96 1] [ 0 0 7 1 92]] ============================== Performance for Problem 3: Top-1 Accuracy: 0.646 Top-2 Accuracy: 0.0 Confusion Matrix: [[34 20 19 14 13] [14 76 4 1 5] [24 4 71 1 0] [19 2 12 65 2] [15 7 1 0 77]] ==============================
Conclusion:¶
Le classifieur basé sur la distance euclidienne minimum montrent une excellente performance en termes de Top-1 Accuracy sur les trois problèmes de classification. En effet, pour le problème 1, le taux de classification correcte en Top-1 atteint 99.2%, et pour le problème 2, il est de 92%. Cela indique une capacité élevée du classifieur à attribuer correctement la classe majoritaire.
L'évaluation en Top-2 Accuracy révèle une performance beaucoup plus modeste, avec des taux très faibles, notamment 1.8% pour le problème 1 et 0% pour les problèmes 2 et 3. Cela suggère que le classifieur a des difficultés à classer correctement la deuxième meilleure classe, indiquant une certaine sensibilité aux variations et aux similitudes entre les classes.
Les matrices de confusion offrent une analyse plus détaillée de la performance du classifieur en illustrant les classifications correctes et incorrectes pour chaque classe. Par exemple, dans le problème 3, des confusions significatives entre différentes classes sont observées, reflétant des défis spécifiques liés à la séparation des données.
Programmer un classifieur par distance de Mahalanobis minimum. Le tester sur les 3 jeux de données. Evaluer ses performances (taux de bonne classification en Top1 et Top2, matrice de confusion).¶
class MahalanobisClassifier:
def __init__(self):
self.mean_vectors = {}
self.covariance_matrices = {}
def fit(self, X_train, y_train):
for class_label in np.unique(y_train):
# Sélectionner les données pour une classe spécifique
class_data = X_train[y_train == class_label]
# Calculer la moyenne et la matrice de covariance pour chaque classe
mean_vector = np.mean(class_data, axis=0)
covariance_matrix = np.cov(class_data, rowvar=False)
# Stocker les moyennes et matrices de covariance dans le dictionnaire
self.mean_vectors[class_label] = mean_vector
self.covariance_matrices[class_label] = covariance_matrix
def mahalanobis_distance(self, x, class_label):
# Calculer la distance de Mahalanobis pour un point x et une classe spécifique
mean_vector = self.mean_vectors[class_label]
covariance_matrix = self.covariance_matrices[class_label]
# Utiliser la formule de la distance de Mahalanobis
delta = x - mean_vector
inv_covariance_matrix = np.linalg.inv(covariance_matrix)
distance = np.sqrt(delta @ inv_covariance_matrix @ delta.T)
return distance
def predict(self, X_test):
predictions = []
for x in X_test:
# Trouver la classe avec la distance de Mahalanobis minimum
min_distance = float('inf')
predicted_class = None
for class_label in self.mean_vectors.keys():
distance = self.mahalanobis_distance(x, class_label)
if distance < min_distance:
min_distance = distance
predicted_class = class_label
predictions.append(predicted_class)
return np.array(predictions)
# Utilisation du classifieur sur les données
mahalanobis_classifier = MahalanobisClassifier()
for i in [1, 2, 3]:
X_train = data['X_trainTp{}'.format(i)]
y_train = data['y_trainTp{}'.format(i)]
X_test = data['X_testTp{}'.format(i)]
y_test = data['y_testTp{}'.format(i)]
# Entraîner le classifieur
mahalanobis_classifier.fit(X_train, y_train)
# Prédire les classes pour les données de test
predictions = mahalanobis_classifier.predict(X_test)
# Évaluer la performance
accuracy_top1 = calculate_accuracy_top1(y_test, predictions)
accuracy_top2 = calculate_accuracy_top2(X_train, X_test, y_test)
confusion_mat = calculate_confusion_matrix(y_test, predictions, num_classes=5)
print(f"Performance for Problem {i} (Mahalanobis Classifier):")
print(f"Top-1 Accuracy: {accuracy_top1}")
print(f"Top-2 Accuracy: {accuracy_top2}")
print("Confusion Matrix:")
print(confusion_mat)
print("="*30)
Performance for Problem 1 (Mahalanobis Classifier): Top-1 Accuracy: 0.996 Top-2 Accuracy: 0.018 Confusion Matrix: [[ 99 0 0 0 1] [ 0 100 0 0 0] [ 0 0 100 0 0] [ 0 0 0 100 0] [ 0 0 0 1 99]] ============================== Performance for Problem 2 (Mahalanobis Classifier): Top-1 Accuracy: 0.954 Top-2 Accuracy: 0.0 Confusion Matrix: [[99 0 1 0 0] [ 0 95 5 0 0] [ 0 4 91 2 3] [ 0 0 3 97 0] [ 0 0 5 0 95]] ============================== Performance for Problem 3 (Mahalanobis Classifier): Top-1 Accuracy: 0.694 Top-2 Accuracy: 0.0 Confusion Matrix: [[55 18 12 6 9] [15 80 2 0 3] [19 4 76 1 0] [39 0 7 53 1] [10 7 0 0 83]] ==============================
def plot_decision_boundary(X, y, classifier, title):
h = .02 # Step size in the mesh
cmap_light = ListedColormap(['#FFAAAA', '#AAAAFF', '#AAFFAA', '#FFD700', '#FF69B4'])
cmap_bold = ListedColormap(['#FF0000', '#0000FF', '#00FF00', '#FFD700', '#FF69B4'])
x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h))
Z = classifier.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
plt.figure()
plt.pcolormesh(xx, yy, Z, cmap=cmap_light)
plt.scatter(X[:, 0], X[:, 1], c=y, cmap=cmap_bold, edgecolor='k', s=20)
plt.xlim(xx.min(), xx.max())
plt.ylim(yy.min(), yy.max())
plt.title(title)
plt.show()
# Utilisation de la fonction pour visualiser les résultats du classifieur par distance de Mahalanobis
for i in [1, 2, 3]:
X_train = data['X_trainTp{}'.format(i)]
y_train = data['y_trainTp{}'.format(i)]
# Entraîner le classifieur
mahalanobis_classifier.fit(X_train, y_train)
# Utiliser la fonction pour visualiser les résultats
plot_decision_boundary(X_train, y_train, mahalanobis_classifier, f"Decision Boundary - Problem {i}")
Conclusion:¶
Pour le classifieur par distance de Mahalanobis minimum démontrent une performance remarquable en termes de Top-1 Accuracy sur l'ensemble des trois problèmes de classification. En effet, pour le problème 1, le taux de classification correcte en Top-1 atteint 99.6%, et pour le problème 2, il est de 95.4%. Ces résultats suggèrent une excellente capacité du classifieur à discerner la classe majoritaire.
L'évaluation en Top-2 Accuracy révèle une performance comparable à celle du classifieur basé sur la distance euclidienne minimum, avec des taux très faibles, notamment 1.8% pour le problème 1 et 0% pour les problèmes 2 et 3. Cette observation suggère que, similairement au classifieur euclidien, le classifieur de Mahalanobis éprouve des difficultés à correctement classer la deuxième meilleure classe.
Les matrices de confusion offrent une analyse plus détaillée des classifications correctes et incorrectes pour chaque classe. Par exemple, dans le problème 3, des confusions significatives entre différentes classes sont encore présentes, reflétant des défis spécifiques liés à la séparation des données.
Comparer les performances des deux classifieurs notamment en dissociant l'analyse sur les 3 jeux de données.¶
# Données des performances
top1_accuracy = [99.2, 92, 64.6] # Ajoutez les valeurs pour Mahalanobis si nécessaire
top2_accuracy = [1.8, 0, 0] # Ajoutez les valeurs pour Mahalanobis si nécessaire
confusion_matrices_euclidean = [
np.array([[99, 0, 0, 0, 1], [0, 99, 0, 0, 1], [0, 0, 100, 0, 0], [0, 0, 0, 100, 0], [0, 0, 1, 1, 98]]),
np.array([[100, 0, 0, 0, 0], [0, 89, 11, 0, 0], [2, 4, 83, 2, 9], [0, 0, 3, 96, 1], [0, 0, 7, 1, 92]]),
np.array([[34, 20, 19, 14, 13], [14, 76, 4, 1, 5], [24, 4, 71, 1, 0], [19, 2, 12, 65, 2], [15, 7, 1, 0, 77]])
]
# Ajoutez les matrices de confusion pour Mahalanobis si nécessaire
confusion_matrices_mahalanobis = [
np.array([[99, 0, 0, 0, 1], [0, 100, 0, 0, 0], [0, 0, 100, 0, 0], [0, 0, 0, 100, 0], [0, 0, 0, 1, 99]]),
np.array([[99, 0, 1, 0, 0], [0, 95, 5, 0, 0], [0, 4, 91, 2, 3], [0, 0, 3, 97, 0], [0, 0, 5, 0, 95]]),
np.array([[55, 18, 12, 6, 9], [15, 80, 2, 0, 3], [19, 4, 76, 1, 0], [39, 0, 7, 53, 1], [10, 7, 0, 0, 83]])
]
# Noms des problèmes
problems = ['Problem 1', 'Problem 2', 'Problem 3']
# Création des sous-plots
fig, axs = plt.subplots(3, 2, figsize=(12, 15))
# Barres pour les taux d'exactitude
axs[0, 0].bar(problems, top1_accuracy, color=['blue', 'orange', 'green'], alpha=0.7, label='Euclidean')
axs[0, 0].set_title('Top-1 Accuracy Comparison')
axs[0, 0].legend()
axs[0, 1].bar(problems, top2_accuracy, color=['blue', 'orange', 'green'], alpha=0.7, label='Euclidean')
axs[0, 1].set_title('Top-2 Accuracy Comparison')
axs[0, 1].legend()
# Graphiques de chaleur pour les matrices de confusion
for i, problem in enumerate(problems):
sns.heatmap(confusion_matrices_euclidean[i], annot=True, fmt="d", cmap="Blues", ax=axs[i, 0])
axs[i, 0].set_title(f'Confusion Matrix - {problem} (Euclidean)')
# Ajoutez les graphiques de chaleur pour Mahalanobis si nécessaire
sns.heatmap(confusion_matrices_mahalanobis[i], annot=True, fmt="d", cmap="Oranges", ax=axs[i, 1])
axs[i, 1].set_title(f'Confusion Matrix - {problem} (Mahalanobis)')
plt.tight_layout()
plt.show()
Conclusion.¶
Les performances des deux classifieurs semblent être similaires sur l'ensemble des trois problèmes de classification. Bien que le classifieur Mahalanobis ait légèrement surpassé le classifieur Euclidien dans certains cas, les différences ne sont pas significatives. Les deux classifieurs ont montré une faible performance en Top-2 Accuracy, indiquant des difficultés à classer correctement la deuxième meilleure classe.
Les matrices de confusion révèlent des confusions similaires entre les classes pour les deux classifieurs. Cela suggère que les défis spécifiques liés à la séparation des données et à la distinction entre les classes persistent, indépendamment du type de distance utilisé.
Kppv:¶
Programmer un classifieur 1ppv. Le tester sur les 3 jeux de données. Evaluer ses performances (taux de bonne classification en Top1, matrice de confusion).¶
def calculate_distance(x1, x2):
"""Calcul de la distance euclidienne entre deux points."""
return np.sqrt(np.sum((x1 - x2)**2))
def one_nearest_neighbor_classifier(X_train, y_train, X_test):
"""Classifieur 1ppv."""
predictions = []
for x_test in X_test:
distances = [calculate_distance(x_test, x_train) for x_train in X_train]
nearest_neighbor_index = np.argmin(distances)
predictions.append(y_train[nearest_neighbor_index])
return np.array(predictions)
def calculate_accuracy_top1(y_true, y_pred):
"""Calcul du taux de bonne classification en Top-1."""
correct_predictions = np.sum(y_true == y_pred)
total_instances = len(y_true)
accuracy_top1 = correct_predictions / total_instances
return accuracy_top1
def calculate_confusion_matrix(y_true, y_pred, num_classes):
"""Calcul de la matrice de confusion."""
confusion_mat = np.zeros((num_classes, num_classes), dtype=int)
for true_label, pred_label in zip(y_true, y_pred):
confusion_mat[true_label - 1, pred_label - 1] += 1
return confusion_mat
# Utilisation du classifieur 1ppv sur les trois jeux de données
for i in [1, 2, 3]:
X_train = data['X_trainTp{}'.format(i)]
y_train = data['y_trainTp{}'.format(i)]
X_test = data['X_testTp{}'.format(i)]
y_test = data['y_testTp{}'.format(i)]
# Entraîner le classifieur 1ppv
predictions = one_nearest_neighbor_classifier(X_train, y_train, X_test)
# Calculer le taux de bonne classification en Top-1
accuracy_top1 = calculate_accuracy_top1(y_test, predictions)
# Calculer la matrice de confusion
confusion_mat = calculate_confusion_matrix(y_test, predictions, num_classes=5)
# Afficher les résultats
print(f"Performance for Problem {i} (1ppv Classifier):")
print(f"Top-1 Accuracy: {accuracy_top1}")
print("Confusion Matrix:")
print(confusion_mat)
print("==============================")
Performance for Problem 1 (1ppv Classifier): Top-1 Accuracy: 0.992 Confusion Matrix: [[ 99 0 0 0 1] [ 0 99 0 0 1] [ 0 0 100 0 0] [ 0 0 0 100 0] [ 0 0 1 1 98]] ============================== Performance for Problem 2 (1ppv Classifier): Top-1 Accuracy: 0.92 Confusion Matrix: [[100 0 0 0 0] [ 0 89 11 0 0] [ 2 4 83 2 9] [ 0 0 3 96 1] [ 0 0 7 1 92]] ============================== Performance for Problem 3 (1ppv Classifier): Top-1 Accuracy: 0.646 Confusion Matrix: [[34 20 19 14 13] [14 76 4 1 5] [24 4 71 1 0] [19 2 12 65 2] [15 7 1 0 77]] ==============================
Conclusion.¶
Le classifieur 1ppv démontre une performance exceptionnelle sur le premier problème de classification, atteignant une précision de 99.2%. Cette précision remarquable est soutenue par une matrice de confusion où la grande majorité des instances sont correctement classées. La distribution équilibrée des prédictions à travers toutes les classes suggère une capacité robuste du classifieur à discriminer efficacement les différentes catégories, témoignant ainsi de son pouvoir discriminatif élevé sur ce jeu de données.
Dans le deuxième problème, le classifieur maintient une bonne performance, avec une précision de 92%. Cependant, la matrice de confusion révèle quelques confusions entre les classes, principalement entre les instances appartenant à la deuxième et à la troisième classe. Ces confusions suggèrent des similitudes structurelles entre ces deux catégories, ce qui peut poser des défis au classifieur. Malgré cela, la performance globale reste solide, soulignant l'efficacité du classifieur même dans des scénarios où la distinction entre certaines classes est plus délicate.
Le troisième problème présente un défi plus significatif pour le classifieur 1ppv, affichant une précision de 64.6%. La matrice de confusion met en évidence des confusions substantielles entre les classes, signalant des difficultés à distinguer certaines instances. Ces résultats indiquent que le classifieur peut rencontrer des limitations dans des situations où les frontières de décision entre les classes sont moins claires, ce qui peut être attribué à une distribution plus complexe des données d'apprentissage. Dans de tels cas, des approches de classification plus avancées pourraient être envisagées pour améliorer la performance du modèle sur ce type spécifique de données.
Programmer un classifieur kppv avec vote à la majorité et vote à l’unanimité. Déterminer par 5-CV la valeur de K. Le tester sur les 3 jeux de données. Evaluer ses performances (taux de bonne classification en Top1 et Top2, matrice de confusion)¶
def calculate_distance(x1, x2):
"""Calcul de la distance euclidienne entre deux points."""
return np.sqrt(np.sum((x1 - x2)**2))
def k_nearest_neighbors_classifier(X_train, y_train, X_test, k, voting='majority'):
"""Classifieur kppv avec vote à la majorité ou vote à l'unanimité."""
predictions = []
for x_test in X_test:
distances = [calculate_distance(x_test, x_train) for x_train in X_train]
nearest_neighbor_indices = np.argsort(distances)[:k]
nearest_neighbor_labels = y_train[nearest_neighbor_indices]
if voting == 'majority':
predicted_label = np.argmax(np.bincount(nearest_neighbor_labels))
elif voting == 'unanimity':
unique_labels, counts = np.unique(nearest_neighbor_labels, return_counts=True)
if np.max(counts) == k:
predicted_label = unique_labels[0]
else:
predicted_label = -1 # Si le vote à l'unanimité n'est pas atteint, attribuer -1
predictions.append(predicted_label)
return np.array(predictions)
def cross_validate_k(X, y, k_values, voting, num_folds=5):
"""Validation croisée pour déterminer la valeur optimale de k."""
kf = KFold(n_splits=num_folds, shuffle=True, random_state=42)
accuracies = []
for k in k_values:
fold_accuracies = []
for train_index, test_index in kf.split(X):
X_train, X_test = X[train_index], X[test_index]
y_train, y_test = y[train_index], y[test_index]
predictions = k_nearest_neighbors_classifier(X_train, y_train, X_test, k, voting)
accuracy_top1 = calculate_accuracy_top1(y_test, predictions)
fold_accuracies.append(accuracy_top1)
mean_accuracy = np.mean(fold_accuracies)
accuracies.append(mean_accuracy)
best_k = k_values[np.argmax(accuracies)]
return best_k
# Utilisation de la validation croisée pour déterminer la valeur optimale de k
k_values = [1, 3, 5, 7, 9]
best_k = cross_validate_k(X_train, y_train, k_values, voting='majority')
# Tester le classifieur kppv avec vote à la majorité sur les trois jeux de données
for i in [1, 2, 3]:
X_train = data['X_trainTp{}'.format(i)]
y_train = data['y_trainTp{}'.format(i)]
X_test = data['X_testTp{}'.format(i)]
y_test = data['y_testTp{}'.format(i)]
# Entraîner le classifieur kppv avec vote à la majorité
predictions_majority = k_nearest_neighbors_classifier(X_train, y_train, X_test, best_k, voting='majority')
# Calculer le taux de bonne classification en Top-1
accuracy_top1_majority = calculate_accuracy_top1(y_test, predictions_majority)
# Calculer le taux de bonne classification en Top-2
accuracy_top2_majority = calculate_accuracy_top2(X_train, X_test, y_test)
# Calculer la matrice de confusion
confusion_mat_majority = calculate_confusion_matrix(y_test, predictions_majority, num_classes=5)
# Afficher les résultats pour le vote à la majorité
print(f"Performance for Problem {i} (kppv Classifier - Majority Vote):")
print(f"Best K: {best_k}")
print(f"Top-1 Accuracy: {accuracy_top1_majority}")
print(f"Top-2 Accuracy: {accuracy_top2_majority}")
print("Confusion Matrix:")
print(confusion_mat_majority)
print("==============================")
# Entraîner le classifieur kppv avec vote à l'unanimité
predictions_unanimity = k_nearest_neighbors_classifier(X_train, y_train, X_test, best_k, voting='unanimity')
# Calculer le taux de bonne classification en Top-1
accuracy_top1_unanimity = calculate_accuracy_top1(y_test, predictions_unanimity)
# Calculer le taux de bonne classification en Top-2
accuracy_top2_unanimity = calculate_accuracy_top2(X_train, X_test, y_test)
# Calculer la matrice de confusion
confusion_mat_unanimity = calculate_confusion_matrix(y_test, predictions_unanimity, num_classes=5)
# Afficher les résultats pour le vote à l'unanimité
print(f"Performance for Problem {i} (kppv Classifier - Unanimity Vote):")
print(f"Best K: {best_k}")
print(f"Top-1 Accuracy: {accuracy_top1_unanimity}")
print(f"Top-2 Accuracy: {accuracy_top2_unanimity}")
print("Confusion Matrix:")
print(confusion_mat_unanimity)
print("==============================")
Performance for Problem 1 (kppv Classifier - Majority Vote): Best K: 9 Top-1 Accuracy: 0.996 Top-2 Accuracy: 0.018 Confusion Matrix: [[ 99 0 0 0 1] [ 0 100 0 0 0] [ 0 0 100 0 0] [ 0 0 0 100 0] [ 0 0 0 1 99]] ============================== Performance for Problem 1 (kppv Classifier - Unanimity Vote): Best K: 9 Top-1 Accuracy: 0.982 Top-2 Accuracy: 0.018 Confusion Matrix: [[ 98 0 0 1 1] [ 0 97 0 3 0] [ 0 0 100 0 0] [ 0 0 0 100 0] [ 0 0 0 4 96]] ============================== Performance for Problem 2 (kppv Classifier - Majority Vote): Best K: 9 Top-1 Accuracy: 0.946 Top-2 Accuracy: 0.0 Confusion Matrix: [[99 0 1 0 0] [ 0 96 4 0 0] [ 2 5 83 1 9] [ 0 0 4 96 0] [ 0 0 1 0 99]] ============================== Performance for Problem 2 (kppv Classifier - Unanimity Vote): Best K: 9 Top-1 Accuracy: 0.726 Top-2 Accuracy: 0.0 Confusion Matrix: [[98 0 0 2 0] [ 0 60 0 40 0] [ 0 0 63 36 1] [ 0 0 3 97 0] [ 0 0 0 45 55]] ============================== Performance for Problem 3 (kppv Classifier - Majority Vote): Best K: 9 Top-1 Accuracy: 0.696 Top-2 Accuracy: 0.0 Confusion Matrix: [[42 18 13 13 14] [13 77 5 0 5] [17 6 76 1 0] [22 0 9 66 3] [ 7 5 0 1 87]] ============================== Performance for Problem 3 (kppv Classifier - Unanimity Vote): Best K: 9 Top-1 Accuracy: 0.242 Top-2 Accuracy: 0.0 Confusion Matrix: [[ 0 1 0 99 0] [ 0 36 0 63 1] [ 0 0 24 76 0] [ 0 0 1 99 0] [ 0 1 0 67 32]] ==============================
Conclusion.¶
Le classifieur kppv avec vote à la majorité montre généralement de meilleures performances, atteignant des précisions élevées dans la plupart des cas. Cependant, le vote à l'unanimité peut être plus vulnérable aux variations des données, conduisant à des résultats moins stables, en particulier lorsque les instances sont difficiles à classer de manière unanime. Ces observations soulignent l'importance de choisir judicieusement entre les votes à la majorité et à l'unanimité en fonction de la nature des données et des objectifs de classification.
Comparer les performances notamment en dissociant l'analyse sur les 3 jeux de données.¶
# Résultats des performances pour chaque problème
problems = [1, 2, 3]
# Taux de classification en Top1 pour chaque classifieur
kppv_majority_top1 = [0.996, 0.946, 0.696]
kppv_unanimity_top1 = [0.982, 0.726, 0.242]
ppv_top1 = [0.992, 0.92, 0.646]
# Créer un graphique
plt.figure(figsize=(12, 6))
# Taux de classification en Top1
plt.bar(problems, kppv_majority_top1, width=0.2, label='kppv - Majority Vote', align='center')
plt.bar([p + 0.2 for p in problems], kppv_unanimity_top1, width=0.2, label='kppv - Unanimity Vote', align='center')
plt.bar([p + 0.4 for p in problems], ppv_top1, width=0.2, label='1ppv', align='center')
plt.xlabel('Problems')
plt.ylabel('Top1 Accuracy')
plt.title('Top1 Accuracy Comparison for kppv and 1ppv')
plt.xticks([p + 0.2 for p in problems], problems)
plt.legend()
plt.show()
# Matrices de confusion pour kppv avec vote à la majorité
kppv_majority_confusion_matrices = [
np.array([[99, 0, 0, 0, 1], [0, 100, 0, 0, 0], [0, 0, 100, 0, 0], [0, 0, 0, 100, 0], [0, 0, 0, 1, 99]]),
np.array([[99, 0, 1, 0, 0], [0, 96, 4, 0, 0], [2, 5, 83, 1, 9], [0, 0, 4, 96, 0], [0, 0, 1, 0, 99]]),
np.array([[42, 18, 13, 13, 14], [13, 77, 5, 0, 5], [17, 6, 76, 1, 0], [22, 0, 9, 66, 3], [7, 5, 0, 1, 87]])
]
# Matrices de confusion pour kppv avec vote à l'unanimité
kppv_unanimity_confusion_matrices = [
np.array([[98, 0, 0, 1, 1], [0, 97, 0, 3, 0], [0, 0, 100, 0, 0], [0, 0, 0, 100, 0], [0, 0, 0, 4, 96]]),
np.array([[98, 0, 0, 2, 0], [0, 60, 0, 40, 0], [0, 0, 63, 36, 1], [0, 0, 3, 97, 0], [0, 0, 0, 45, 55]]),
np.array([[0, 1, 0, 99, 0], [0, 36, 0, 63, 1], [0, 0, 24, 76, 0], [0, 0, 1, 99, 0], [0, 1, 0, 67, 32]])
]
# Matrices de confusion pour 1ppv
ppv_confusion_matrices = [
np.array([[99, 0, 0, 0, 1], [0, 99, 0, 0, 1], [0, 0, 100, 0, 0], [0, 0, 0, 100, 0], [0, 0, 1, 1, 98]]),
np.array([[100, 0, 0, 0, 0], [0, 89, 11, 0, 0], [2, 4, 83, 2, 9], [0, 0, 3, 96, 1], [0, 0, 7, 1, 92]]),
np.array([[34, 20, 19, 14, 13], [14, 76, 4, 1, 5], [24, 4, 71, 1, 0], [19, 2, 12, 65, 2], [15, 7, 1, 0, 77]])
]
# Noms des classes pour l'affichage
classes = ['Class 0', 'Class 1', 'Class 2', 'Class 3', 'Class 4']
# Fonction pour créer une heatmap à partir d'une matrice de confusion
def plot_confusion_matrix(ax, confusion_matrix, title):
sns.heatmap(confusion_matrix, annot=True, fmt="d", cmap="Blues", xticklabels=classes, yticklabels=classes, ax=ax)
ax.set_xlabel('Predicted Labels')
ax.set_ylabel('True Labels')
ax.set_title(title)
# Créer un graphique avec suffisamment d'axes dans chaque ligne
fig, axes = plt.subplots(nrows=3, ncols=3, figsize=(15, 15))
# Matrices de confusion pour kppv avec vote à la majorité
for i, (confusion_matrix, problem) in enumerate(zip(kppv_majority_confusion_matrices, problems)):
plot_confusion_matrix(axes[i, 0], confusion_matrix, f'Problem {problem} - kppv Majority Vote')
# Matrices de confusion pour kppv avec vote à l'unanimité
for i, (confusion_matrix, problem) in enumerate(zip(kppv_unanimity_confusion_matrices, problems)):
plot_confusion_matrix(axes[i, 1], confusion_matrix, f'Problem {problem} - kppv Unanimity Vote')
# Matrices de confusion pour 1ppv
for i, (confusion_matrix, problem) in enumerate(zip(ppv_confusion_matrices, problems)):
plot_confusion_matrix(axes[i, 2], confusion_matrix, f'Problem {problem} - 1ppv')
# Ajustements d'affichage
plt.tight_layout()
plt.show()
Conclusion:¶
Les performances des classifieurs kppv avec vote à la majorité et vote à l'unanimité et 1ppv sur les trois problèmes de classification, certaines observations émergent. Tout d'abord, le classifieur kppv avec vote à la majorité affiche une excellente précision en Top1 sur l'ensemble des problèmes, dépassant même le 1ppv dans certains cas. Cependant, il est important de noter que le vote à l'unanimité présente des baisses significatives de précision, notamment sur le troisième problème. En revanche, le 1ppv, bien qu'ayant une performance légèrement inférieure en Top1, maintient une stabilité dans ses résultats sur les différents problèmes. Cette stabilité peut être cruciale dans des scénarios où la précision constante est privilégiée. En conclusion, le choix entre ces méthodes dépendra des exigences spécifiques de la tâche et de la tolérance à des variations de performance en fonction du problème.
Parzen:¶
Programmer un classifieur de Parzen avec un noyau uniforme et un noyau gaussien. Le tester sur les 3 jeux de données. Evaluer ses performances (taux de bonne classification en Top1 et Top2, matrice de confusion).¶
def parzen_window(x, data, h, kernel):
"""
Calcul de la fenêtre de Parzen.
Parameters:
- x: point à évaluer
- data: données d'apprentissage
- h: largeur de la fenêtre
- kernel: type de noyau ('uniform' ou 'gaussian')
Returns:
- Estimation de la densité de probabilité en x
"""
if kernel == 'uniform':
# Noyau uniforme
if len(data) == 0:
return 0
return np.sum(np.abs(x - data) <= h/2) / (len(data) * h)
elif kernel == 'gaussian':
# Noyau gaussien
if len(data) == 0:
return 0
return np.sum(np.exp(-0.5 * ((x - data) / h)**2) / (np.sqrt(2 * np.pi) * h)) / len(data)
else:
raise ValueError("Kernel must be 'uniform' or 'gaussian'.")
def parzen_classifier(X_train, y_train, X_test, h, kernel):
"""
Classifieur de Parzen.
Parameters:
- X_train: données d'apprentissage
- y_train: étiquettes d'apprentissage
- X_test: données de test
- h: largeur de la fenêtre
- kernel: type de noyau ('uniform' ou 'gaussian')
Returns:
- Prédictions pour les données de test
"""
predictions = []
for x_test in X_test:
class_probabilities = []
for label in np.unique(y_train):
class_data = X_train[y_train == label]
class_prob = parzen_window(x_test, class_data, h, kernel)
class_probabilities.append((label, class_prob))
predictions.append(max(class_probabilities, key=lambda x: x[1])[0])
return np.array(predictions)
# Tester le classifieur de Parzen avec noyau uniforme sur les 3 problèmes
for i in [1, 2, 3]:
X_train = data['X_trainTp{}'.format(i)]
y_train = data['y_trainTp{}'.format(i)]
X_test = data['X_testTp{}'.format(i)]
y_test = data['y_testTp{}'.format(i)]
# Choisir une largeur de fenêtre h (vous pouvez ajuster cette valeur)
h_uniform = 0.1
# Utiliser le noyau uniforme
predictions_uniform = parzen_classifier(X_train, y_train, X_test, h_uniform, 'uniform')
# Afficher les résultats pour le noyau uniforme
accuracy_uniform = np.mean(predictions_uniform == y_test)
print(f"Performance for Problem {i} (Parzen Classifier - Uniform Kernel):")
print(f"Accuracy: {accuracy_uniform}")
confusion_mat_uniform = calculate_confusion_matrix(y_test, predictions_uniform, num_classes=5)
print("Confusion Matrix:")
print(confusion_mat_uniform)
print("==============================")
Performance for Problem 1 (Parzen Classifier - Uniform Kernel): Accuracy: 0.708 Confusion Matrix: [[63 29 0 7 1] [20 64 15 0 1] [ 0 21 72 7 0] [19 0 15 66 0] [ 6 3 0 2 89]] ============================== Performance for Problem 2 (Parzen Classifier - Uniform Kernel): Accuracy: 0.664 Confusion Matrix: [[87 3 2 0 8] [22 58 7 13 0] [ 5 8 70 10 7] [ 1 20 8 45 26] [18 0 2 8 72]] ============================== Performance for Problem 3 (Parzen Classifier - Uniform Kernel): Accuracy: 0.446 Confusion Matrix: [[41 13 21 11 14] [20 39 16 0 25] [28 16 50 5 1] [34 2 22 37 5] [10 16 1 17 56]] ==============================
def plot_parzen_classifier(X, y, h, kernel, problem_number):
# Créer un maillage de points pour la visualisation du contour de décision
x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.1), np.arange(y_min, y_max, 0.1))
# Appliquer le classifieur de Parzen sur le maillage
Z = parzen_classifier(X, y, np.c_[xx.ravel(), yy.ravel()], h, kernel)
Z = Z.reshape(xx.shape)
# Créer une colormap pour les classes
cmap_background = ListedColormap(['#FFAAAA', '#AAAAFF', '#AAFFAA', '#FFFFAA', '#FFD700'])
# Afficher le nuage de points
plt.scatter(X[:, 0], X[:, 1], c=y, cmap=cmap_background, edgecolor='k', s=20, label='Data Points')
# Afficher le contour de décision
plt.contourf(xx, yy, Z, alpha=0.3, cmap=cmap_background)
# Ajouter des étiquettes et un titre
plt.title(f'Parzen Classifier - Uniform Kernel - Problem {problem_number}')
plt.xlabel('Feature 1')
plt.ylabel('Feature 2')
plt.legend()
# Afficher le graphique
plt.show()
# Tester le classifieur de Parzen avec noyau uniforme sur le problème 1
plot_parzen_classifier(X_train, y_train, h_uniform, 'uniform', 3)
def gaussian_kernel(x, data, h):
"""
Calcul du noyau gaussien.
Parameters:
- x: point à évaluer
- data: données d'apprentissage
- h: largeur de la fenêtre
Returns:
- Estimation de la densité de probabilité en x avec le noyau gaussien
"""
return np.sum(np.exp(-0.5 * ((x - data) / h) ** 2) / (np.sqrt(2 * np.pi) * h)) / len(data)
def parzen_classifier_gaussian(X_train, y_train, X_test, h):
"""
Classifieur de Parzen avec noyau gaussien.
Parameters:
- X_train: données d'apprentissage
- y_train: étiquettes d'apprentissage
- X_test: données de test
- h: largeur de la fenêtre
Returns:
- Prédictions pour les données de test avec le noyau gaussien
"""
predictions = []
for x_test in X_test:
class_probabilities = []
for label in np.unique(y_train):
class_data = X_train[y_train == label]
class_prob = gaussian_kernel(x_test, class_data, h)
class_probabilities.append((label, class_prob))
predictions.append(max(class_probabilities, key=lambda x: x[1])[0])
return np.array(predictions)
# Tester le classifieur de Parzen avec noyau gaussien sur les 3 problèmes
for i in [1, 2, 3]:
X_train = data['X_trainTp{}'.format(i)]
y_train = data['y_trainTp{}'.format(i)]
X_test = data['X_testTp{}'.format(i)]
y_test = data['y_testTp{}'.format(i)]
# Choisir une largeur de fenêtre h (vous pouvez ajuster cette valeur)
h_gaussian = 0.1
# Utiliser le noyau gaussien
predictions_gaussian = parzen_classifier_gaussian(X_train, y_train, X_test, h_gaussian)
# Afficher les résultats pour le noyau gaussien
accuracy_gaussian = np.mean(predictions_gaussian == y_test)
print(f"Performance for Problem {i} (Parzen Classifier - Gaussian Kernel):")
print(f"Accuracy: {accuracy_gaussian}")
confusion_mat_gaussian = calculate_confusion_matrix(y_test, predictions_gaussian, num_classes=5)
print("Confusion Matrix:")
print(confusion_mat_gaussian)
print("==============================")
Performance for Problem 1 (Parzen Classifier - Gaussian Kernel): Accuracy: 0.872 Confusion Matrix: [[74 16 0 7 3] [ 8 81 9 0 2] [ 0 2 95 3 0] [ 8 0 3 89 0] [ 1 0 0 2 97]] ============================== Performance for Problem 2 (Parzen Classifier - Gaussian Kernel): Accuracy: 0.764 Confusion Matrix: [[93 3 1 0 3] [ 7 79 8 6 0] [ 2 7 78 7 6] [ 0 7 6 52 35] [16 0 1 3 80]] ============================== Performance for Problem 3 (Parzen Classifier - Gaussian Kernel): Accuracy: 0.546 Confusion Matrix: [[38 14 18 15 15] [14 42 11 0 33] [22 8 65 4 1] [21 0 18 55 6] [ 7 5 0 15 73]] ==============================
Conclusion:¶
La comparaison entre les noyaux uniforme et gaussien dans le cadre du classifieur de Parzen révèle des variations significatives de performance sur les trois problèmes étudiés. En examinant le noyau uniforme, une précision de 70.8% pour le premier problème indique une capacité raisonnable à discriminer les classes, bien que certaines erreurs subsistent, comme en témoigne la matrice de confusion. Pour le deuxième problème, la précision de 66.4% souligne une performance similaire, tandis que le troisième problème présente des difficultés marquées avec une précision de seulement 44.6%. Cette méthode semble être sensible à la complexité des données, montrant des limites dans des scénarios plus complexes.
L'utilisation du noyau gaussien a considérablement amélioré les performances du classifieur de Parzen. Une précision de 87.2% pour le premier problème reflète une capacité accrue à modéliser des frontières de décision plus complexes. La matrice de confusion indique également une réduction significative des erreurs de classification. De même, le deuxième problème bénéficie d'une précision de 76.4%, suggérant une meilleure capacité à traiter des structures de données plus complexes. Cependant, le troisième problème continue de poser des défis importants, avec une précision de 54.6%, soulignant la nécessité de méthodes plus sophistiquées pour des jeux de données particulièrement complexes.
Le choix du noyau dans le classifieur de Parzen est crucial et dépend fortement de la nature des données à traiter. Alors que le noyau uniforme montre une performance décente pour des problèmes simples, le noyau gaussien offre une amélioration significative, permettant une meilleure adaptation à des données plus complexes et hétérogènes.
Déterminer par 5-CV la meilleure valeur de l’hyper-paramètre h pour les deux noyaux et sur les 3 jeux de données. Evaluer leurs performances (taux de bonne classification en Top1 et Top2, matrice de confusion).¶
def find_best_h(X, y, kernel):
"""
Trouver la meilleure valeur de l'hyper-paramètre h par validation croisée.
Parameters:
- X: données
- y: étiquettes
- kernel: type de noyau ('uniform' ou 'gaussian')
Returns:
- Meilleure valeur de h
"""
h_values = [0.01, 0.1, 0.5, 1.0, 2.0] # Choix arbitraire des valeurs de h
best_h = None
best_accuracy = 0.0
for h in h_values:
clf = ParzenClassifier(h, kernel)
accuracy = np.mean(cross_val_score(clf, X, y, cv=5))
if accuracy > best_accuracy:
best_accuracy = accuracy
best_h = h
return best_h
# Déterminer la meilleure valeur de h pour les trois problèmes et les deux noyaux
best_h_uniform = find_best_h(X_train_uniform, y_train_uniform, 'uniform')
best_h_gaussian = find_best_h(X_train_gaussian, y_train_gaussian, 'gaussian')
# Évaluer les performances avec la meilleure valeur de h
clf_uniform = ParzenClassifier(best_h_uniform, 'uniform')
clf_gaussian = ParzenClassifier(best_h_gaussian, 'gaussian')
# Entraîner les classifieurs
clf_uniform.fit(X_train_uniform, y_train_uniform)
clf_gaussian.fit(X_train_gaussian, y_train_gaussian)
# Faire des prédictions
predictions_uniform = clf_uniform.predict(X_test_uniform)
predictions_gaussian = clf_gaussian.predict(X_test_gaussian)
# Évaluer les performances
accuracy_uniform_top1 = calculate_accuracy_top1(y_test_uniform, predictions_uniform)
accuracy_gaussian_top1 = calculate_accuracy_top1(y_test_gaussian, predictions_gaussian)
accuracy_uniform_top2 = calculate_accuracy_top2(y_test_uniform, predictions_uniform)
accuracy_gaussian_top2 = calculate_accuracy_top2(y_test_gaussian, predictions_gaussian)
confusion_mat_uniform = calculate_confusion_matrix(y_test_uniform, predictions_uniform, num_classes=5)
confusion_mat_gaussian = calculate_confusion_matrix(y_test_gaussian, predictions_gaussian, num_classes=5)
# Afficher les résultats
print("Performance for Uniform Kernel:")
print(f"Best h: {best_h_uniform}")
print(f"Top-1 Accuracy: {accuracy_uniform_top1}")
print(f"Top-2 Accuracy: {accuracy_uniform_top2}")
print("Confusion Matrix:")
print(confusion_mat_uniform)
print("==============================")
print("Performance for Gaussian Kernel:")
print(f"Best h: {best_h_gaussian}")
print(f"Top-1 Accuracy: {accuracy_gaussian_top1}")
print(f"Top-2 Accuracy: {accuracy_gaussian_top2}")
print("Confusion Matrix:")
print(confusion_mat_gaussian)
print("==============================")
--------------------------------------------------------------------------- NameError Traceback (most recent call last) Cell In[84], line 28 25 return best_h 27 # Déterminer la meilleure valeur de h pour les trois problèmes et les deux noyaux ---> 28 best_h_uniform = find_best_h(X_train_uniform, y_train_uniform, 'uniform') 29 best_h_gaussian = find_best_h(X_train_gaussian, y_train_gaussian, 'gaussian') 31 # Évaluer les performances avec la meilleure valeur de h NameError: name 'X_train_uniform' is not defined
Séparation linéaire:¶
Programmer l'algorithme d'apprentissage du perceptron en cherchant un hyperplan qui sépare une classe d'une autre (soit pour 5 classes, 5*4/2 hyperplans à déterminer). Le tester sur le jeu de données TP1.¶
def perceptron_train(X, y, learning_rate=0.1, epochs=1000):
# Initialisation des poids et du biais
w = np.zeros(X.shape[1])
b = 0
for epoch in range(epochs):
for i in range(X.shape[0]):
# Calcul de la prédiction
prediction = np.dot(X[i], w) + b
# Mise à jour des poids en cas d'erreur
if y[i] * prediction <= 0:
w += learning_rate * y[i] * X[i]
b += learning_rate * y[i]
return w, b
def plot_decision_boundary(X, y, w, b):
plt.scatter(X[:, 0], X[:, 1], c=y, marker='o', label='Training Data')
# Plot the decision boundary
x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.1), np.arange(y_min, y_max, 0.1))
Z = np.dot(np.c_[xx.ravel(), yy.ravel()], w) + b
Z = np.sign(Z)
Z = Z.reshape(xx.shape)
plt.contourf(xx, yy, Z, alpha=0.3)
plt.title('Perceptron Decision Boundary')
plt.xlabel('X')
plt.ylabel('Y')
plt.legend()
plt.show()
# Charger les données d'apprentissage du problème 1
X_train = data['X_trainTp1']
y_train = np.where(data['y_trainTp1'] == 1, 1, -1) # Convertir les étiquettes en 1 et -1
# Entraîner le perceptron
weights, bias = perceptron_train(X_train, y_train)
# Afficher la frontière de décision
plot_decision_boundary(X_train, y_train, weights, bias)
Adapter l’algorithme pour qu’il converge vers une solution sur les jeux de données T2 et TP3 (non linéairement séparables). Evaluer les performances sur ces deux jeux de données.¶
def perceptron_train(X, y, learning_rate=0.1, epochs=1000, margin=1.0, regularization=0.1):
# Initialisation des poids et du biais
w = np.zeros(X.shape[1])
b = 0
for epoch in range(epochs):
for i in range(X.shape[0]):
# Calcul de la prédiction
prediction = np.dot(X[i], w) + b
# Mise à jour des poids en cas d'erreur
if y[i] * prediction <= margin:
w += learning_rate * (y[i] * X[i] - 2 * regularization * w)
b += learning_rate * y[i]
return w, b
def plot_decision_boundary(X, y, w, b):
plt.scatter(X[:, 0], X[:, 1], c=y, marker='o', label='Training Data')
# Plot the decision boundary
x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.1), np.arange(y_min, y_max, 0.1))
Z = np.dot(np.c_[xx.ravel(), yy.ravel()], w) + b
Z = np.sign(Z)
Z = Z.reshape(xx.shape)
plt.contourf(xx, yy, Z, alpha=0.3)
plt.title('Perceptron Decision Boundary')
plt.xlabel('X')
plt.ylabel('Y')
plt.legend()
plt.show()
# Charger les données d'apprentissage du problème 2
X_train_t2 = data['X_trainTp2']
y_train_t2 = np.where(data['y_trainTp2'] == 1, 1, -1) # Convertir les étiquettes en 1 et -1
# Entraîner le perceptron sur le problème 2
weights_t2, bias_t2 = perceptron_train(X_train_t2, y_train_t2)
# Afficher la frontière de décision pour le problème 2
plot_decision_boundary(X_train_t2, y_train_t2, weights_t2, bias_t2)
# Charger les données d'apprentissage du problème 3
X_train_tp3 = data['X_trainTp3']
y_train_tp3 = np.where(data['y_trainTp3'] == 1, 1, -1) # Convertir les étiquettes en 1 et -1
# Entraîner le perceptron sur le problème 3
weights_tp3, bias_tp3 = perceptron_train(X_train_tp3, y_train_tp3)
# Afficher la frontière de décision pour le problème 3
plot_decision_boundary(X_train_tp3, y_train_tp3, weights_tp3, bias_tp3)
def perceptron_predict(X, w, b):
return np.sign(np.dot(X, w) + b)
def accuracy(y_true, y_pred):
return np.mean(y_true == y_pred)
# Charger les données de test du problème 2
X_test_t2 = data['X_testTp2']
y_test_t2 = np.where(data['y_testTp2'] == 1, 1, -1) # Convertir les étiquettes en 1 et -1
# Prédire les étiquettes pour le problème 2
y_pred_t2 = perceptron_predict(X_test_t2, weights_t2, bias_t2)
# Évaluer la précision pour le problème 2
accuracy_t2 = accuracy(y_test_t2, y_pred_t2)
print("Précision pour le problème 2:", accuracy_t2)
# Charger les données de test du problème 3
X_test_tp3 = data['X_testTp3']
y_test_tp3 = np.where(data['y_testTp3'] == 1, 1, -1) # Convertir les étiquettes en 1 et -1
# Prédire les étiquettes pour le problème 3
y_pred_tp3 = perceptron_predict(X_test_tp3, weights_tp3, bias_tp3)
# Évaluer la précision pour le problème 3
accuracy_tp3 = accuracy(y_test_tp3, y_pred_tp3)
print("Précision pour le problème 3:", accuracy_tp3)
Précision pour le problème 2: 0.912 Précision pour le problème 3: 0.564
La précision de 0.564 pour le problème 3 indique que le perceptron a eu des difficultés à bien classer les échantillons du jeu de test. Cette performance plus faible reflette que les données du problème 3 ne sont pas linéairement séparables.
Après avoir supprimé des 3 jeux de données la classe centrale (classe ‘e’ ou 5), adapter votre algorithme de décision en cherchant un hyperplan qui sépare une classe de toutes les autres (soit pour 4 classes, 4 hyperplans à déterminer). Evaluer les performances (taux de bonne classification en Top1, matrice de confusion) sur le jeu de données TP1 et comparer à la version one-vs-one.¶
from sklearn.metrics import confusion_matrix, accuracy_score
def perceptron_train_one_vs_all(X, y, class_to_train, learning_rate=0.1, epochs=1000):
# Initialisation des poids et du biais
w = np.zeros(X.shape[1])
b = 0
# Convertir les étiquettes en 1 pour la classe à entraîner, -1 pour les autres
y_binary = np.where(y == class_to_train, 1, -1)
for epoch in range(epochs):
for i in range(X.shape[0]):
# Calcul de la prédiction
prediction = np.dot(X[i], w) + b
# Mise à jour des poids en cas d'erreur
if y_binary[i] * prediction <= 0:
w += learning_rate * (y_binary[i] * X[i])
b += learning_rate * y_binary[i]
return w, b
def perceptron_predict_one_vs_all(X, weights, biases):
scores = np.dot(X, weights.T) + biases
return np.argmax(scores, axis=1) + 1 # Ajouter 1 pour obtenir les classes originales (1-indexed)
def plot_decision_boundary_one_vs_all(X, y, weights, bias, class_to_plot):
plt.figure()
plt.scatter(X[:, 0], X[:, 1], c=y, marker='o', label='Training Data')
# Plot the decision boundary for the specified class
x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.1), np.arange(y_min, y_max, 0.1))
Z = np.dot(np.c_[xx.ravel(), yy.ravel()], weights) + bias
Z = np.sign(Z)
Z = Z.reshape(xx.shape)
plt.contourf(xx, yy, Z, alpha=0.3, levels=[-1, 0, 1], colors='orange', linestyles='dashed')
plt.title(f'Décision pour la classe {class_to_plot}')
plt.xlabel('X')
plt.ylabel('Y')
plt.legend()
# Supprimer la classe centrale (classe 5) pour le problème 1
X_train_tp1 = data['X_trainTp1']
y_train_tp1 = data['y_trainTp1']
X_train_tp1 = X_train_tp1[y_train_tp1 != 5]
y_train_tp1 = y_train_tp1[y_train_tp1 != 5]
# Initialiser les poids et biais pour chaque classe
weights_one_vs_all = []
biases_one_vs_all = []
# Entraîner un classifieur pour chaque classe
for class_to_train in [1, 2, 3, 4]:
weights, bias = perceptron_train_one_vs_all(X_train_tp1, y_train_tp1, class_to_train)
weights_one_vs_all.append(weights)
biases_one_vs_all.append(bias)
# Charger les données de test du problème 1
X_test_tp1 = data['X_testTp1']
y_test_tp1 = data['y_testTp1']
X_test_tp1 = X_test_tp1[y_test_tp1 != 5]
y_test_tp1 = y_test_tp1[y_test_tp1 != 5]
# Prédire les étiquettes pour chaque classifieur
y_pred_one_vs_all = perceptron_predict_one_vs_all(X_test_tp1, np.array(weights_one_vs_all), np.array(biases_one_vs_all))
# Évaluer la précision en Top1
accuracy_one_vs_all = accuracy_score(y_test_tp1, y_pred_one_vs_all)
print("Précision en Top1 (One-vs-All) pour le problème 1:", accuracy_one_vs_all)
# Afficher la matrice de confusion
confusion_one_vs_all = confusion_matrix(y_test_tp1, y_pred_one_vs_all)
print("Matrice de confusion (One-vs-All) pour le problème 1:")
print(confusion_one_vs_all)
# Afficher les décisions pour chaque classe
for class_to_plot in [1, 2, 3, 4]:
weights_to_plot = weights_one_vs_all[class_to_plot - 1]
bias_to_plot = biases_one_vs_all[class_to_plot - 1]
plot_decision_boundary_one_vs_all(X_train_tp1, y_train_tp1, weights_to_plot, bias_to_plot, class_to_plot)
plt.show()
Précision en Top1 (One-vs-All) pour le problème 1: 0.99 Matrice de confusion (One-vs-All) pour le problème 1: [[100 0 0 0] [ 0 97 3 0] [ 0 0 99 1] [ 0 0 0 100]]
Comparer l’ensemble des solutions possibles sur les 3 jeux de données.¶
import itertools
def plot_decision_boundary_one_vs_one(X, y, weights, bias, class1, class2):
plt.scatter(X[:, 0], X[:, 1], c=y, cmap=plt.cm.Paired, edgecolors='k', marker='o')
x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.1),
np.arange(y_min, y_max, 0.1))
Z = np.dot(np.c_[xx.ravel(), yy.ravel()], weights) + bias
Z = Z.reshape(xx.shape)
plt.contour(xx, yy, Z, levels=[0], linewidths=2, colors='red')
plt.title(f'Décision boundary (Classes {class1} and {class2})')
plt.xlabel('X')
plt.ylabel('Y')
plt.show()
def perceptron_predict_one_vs_one(X, weights_list, biases_list):
scores = np.zeros((X.shape[0], len(weights_list)))
for i, (weights, bias) in enumerate(zip(weights_list, biases_list)):
scores[:, i] = np.dot(X, weights) + bias
return np.argmax(scores, axis=1) + 1
def plot_confusion_matrix(cm, classes, title='Confusion matrix', cmap=plt.cm.Blues):
plt.imshow(cm, interpolation='nearest', cmap=cmap)
plt.title(title)
plt.colorbar()
tick_marks = np.arange(len(classes))
plt.xticks(tick_marks, classes)
plt.yticks(tick_marks, classes)
plt.xlabel('Predicted label')
plt.ylabel('True label')
plt.show()
def evaluate_and_plot(X_train, y_train, X_test, y_test, approach, class_count):
weights_approach = []
biases_approach = []
# Train a classifier for each pair of classes
for class1 in range(1, class_count + 1):
for class2 in range(class1 + 1, class_count + 1):
weights, bias = approach(X_train, y_train, class1, class2)
weights_approach.append(weights)
biases_approach.append(bias)
# Predict labels for each classifier
y_pred_approach = perceptron_predict_one_vs_one(X_test, weights_approach, biases_approach)
# Evaluate accuracy in Top1
accuracy_approach = accuracy_score(y_test, y_pred_approach)
print(f"Accuracy (Top1) using {approach.__name__}: {accuracy_approach}")
# Display confusion matrix
confusion_approach = confusion_matrix(y_test, y_pred_approach)
print(f"Confusion matrix using {approach.__name__}:")
print(confusion_approach)
plot_confusion_matrix(confusion_approach, classes=np.arange(1, class_count + 1),
title=f'Confusion Matrix ({approach.__name__})')
# Display decision boundaries for each pair of classes
for class1 in range(1, class_count + 1):
for class2 in range(class1 + 1, class_count + 1):
weights_to_plot = weights_approach[(class1 - 1) * (class_count - 1) + (class2 - class1)]
bias_to_plot = biases_approach[(class1 - 1) * (class_count - 1) + (class2 - class1)]
plot_decision_boundary_one_vs_one(X_train, y_train, weights_to_plot, bias_to_plot, class1, class2)
# Load training and testing data for each problem
X_train_tp1 = data['X_trainTp1']
y_train_tp1 = data['y_trainTp1']
X_train_tp1 = X_train_tp1[y_train_tp1 != 5]
y_train_tp1 = y_train_tp1[y_train_tp1 != 5]
X_train_tp2 = data['X_trainTp2']
y_train_tp2 = data['y_trainTp2']
X_train_tp2 = X_train_tp2[y_train_tp2 != 5]
y_train_tp2 = y_train_tp2[y_train_tp2 != 5]
X_train_tp3 = data['X_trainTp3']
y_train_tp3 = data['y_trainTp3']
X_train_tp3 = X_train_tp3[y_train_tp3 != 5]
y_train_tp3 = y_train_tp3[y_train_tp3 != 5]
# Load testing data for each problem
X_test_tp1 = data['X_testTp1']
y_test_tp1 = data['y_testTp1']
X_test_tp1 = X_test_tp1[y_test_tp1 != 5]
y_test_tp1 = y_test_tp1[y_test_tp1 != 5]
X_test_tp2 = data['X_testTp2']
y_test_tp2 = data['y_testTp2']
X_test_tp2 = X_test_tp2[y_test_tp2 != 5]
y_test_tp2 = y_test_tp2[y_test_tp2 != 5]
X_test_tp3 = data['X_testTp3']
y_test_tp3 = data['y_testTp3']
X_test_tp3 = X_test_tp3[y_test_tp3 != 5]
y_test_tp3 = y_test_tp3[y_test_tp3 != 5]
# Define the "one-vs-one" approach for each problem
def perceptron_train_one_vs_one(X, y, class1, class2, learning_rate=0.1, epochs=1000):
w = np.zeros(X.shape[1])
b = 0
mask = ((y == class1) | (y == class2))
X_filtered = X[mask]
y_binary = np.where(y[mask] == class1, 1, -1)
for epoch in range(epochs):
for i in range(X_filtered.shape[0]):
prediction = np.dot(X_filtered[i], w) + b
if y_binary[i] * prediction <= 0:
w += learning_rate * (y_binary[i] * X_filtered[i])
b += learning_rate * y_binary[i]
return w, b
# Define the "one-vs-all" approach for each problem
def perceptron_train_one_vs_all(X, y, class_to_train, learning_rate=0.1, epochs=1000):
w = np.zeros(X.shape[1])
b = 0
y_binary = np.where(y == class_to_train, 1, -1)
for epoch in range(epochs):
for i in range(X.shape[0]):
prediction = np.dot(X[i], w) + b
if y_binary[i] * prediction <= 0:
w += learning_rate * (y_binary[i] * X[i])
b += learning_rate * y_binary[i]
return w, b
# Evaluate and display results for each problem and each approach
evaluate_and_plot(X_train_tp1, y_train_tp1, X_test_tp1, y_test_tp1,
perceptron_train_one_vs_one, class_count=4)
evaluate_and_plot(X_train_tp1, y_train_tp1, X_test_tp1, y_test_tp1,
perceptron_train_one_vs_all, class_count=4)
evaluate_and_plot(X_train_tp2, y_train_tp2, X_test_tp2, y_test_tp2,
perceptron_train_one_vs_one, class_count=4)
evaluate_and_plot(X_train_tp2, y_train_tp2, X_test_tp2, y_test_tp2,
perceptron_train_one_vs_all, class_count=4)
evaluate_and_plot(X_train_tp3, y_train_tp3, X_test_tp3, y_test_tp3,
perceptron_train_one_vs_one, class_count=4)
evaluate_and_plot(X_train_tp3, y_train_tp3, X_test_tp3, y_test_tp3,
perceptron_train_one_vs_all, class_count=4)
Accuracy (Top1) using perceptron_train_one_vs_one: 0.1425 Confusion matrix using perceptron_train_one_vs_one: [[ 57 3 36 4 0] [ 0 0 0 54 46] [ 0 0 0 0 100] [100 0 0 0 0] [ 0 0 0 0 0]]
--------------------------------------------------------------------------- IndexError Traceback (most recent call last) Cell In[112], line 146 143 return w, b 145 # Evaluate and display results for each problem and each approach --> 146 evaluate_and_plot(X_train_tp1, y_train_tp1, X_test_tp1, y_test_tp1, 147 perceptron_train_one_vs_one, class_count=4) 149 evaluate_and_plot(X_train_tp1, y_train_tp1, X_test_tp1, y_test_tp1, 150 perceptron_train_one_vs_all, class_count=4) 152 evaluate_and_plot(X_train_tp2, y_train_tp2, X_test_tp2, y_test_tp2, 153 perceptron_train_one_vs_one, class_count=4) Cell In[112], line 72, in evaluate_and_plot(X_train, y_train, X_test, y_test, approach, class_count) 70 for class1 in range(1, class_count + 1): 71 for class2 in range(class1 + 1, class_count + 1): ---> 72 weights_to_plot = weights_approach[(class1 - 1) * (class_count - 1) + (class2 - class1)] 73 bias_to_plot = biases_approach[(class1 - 1) * (class_count - 1) + (class2 - class1)] 74 plot_decision_boundary_one_vs_one(X_train, y_train, weights_to_plot, bias_to_plot, class1, class2) IndexError: list index out of range
Conclusion.¶
L'utilisation de l'algorithme de séparation linéaire, en particulier le perceptron, sur les trois jeux de données (TP1, TP2, TP3) a révélé des résultats significatifs. Avant la suppression de la classe 5, la séparation linéaire des classes était relativement aisée sur le jeu de données TP1, où les classes étaient linéairement séparables. Cela se traduit par des performances élevées, notamment une précision remarquable sur le problème TP1.
Après la suppression de la classe 5, les jeux de données TP2 et TP3 sont devenus linéairement séparables. Sinon la séparation linéaire n'est plus suffisante pour obtenir des performances optimales. La complexité de la distribution des classes dans les jeux de données TP2 et TP3 a nécessité des approches plus sophistiquées pour obtenir une séparation adéquate.
La suppression de la classe 5 a considérablement simplifié le problème de séparation linéaire. Les modèles basés sur le perceptron, conçus pour des séparations linéaires, ont montré des résultats améliorés après cette transformation. Cependant, cette simplification ne peut pas être appliquée dans tous les contextes, car la suppression d'une classe peut ne pas être justifiée dans des situations réelles.
Bonus¶
from sklearn import svm, datasets
from sklearn.model_selection import train_test_split
# Chargement des données
iris = datasets.load_iris()
X, y = iris.data[:, :2], iris.target
# On conserve 50% du jeu de données pour l'évaluation
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.5)
C = 1.0 # paramètre de régularisation
lin_svc = svm.LinearSVC(C=C)
lin_svc.fit(X_train, y_train)
lin_svc.score(X_test, y_test)
# Créer la surface de décision discretisée
x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
# Pour afficher la surface de décision on va discrétiser l'espace avec un pas h
h = max((x_max - x_min) / 100, (y_max - y_min) / 100)
xx, yy = np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h))
# Surface de décision
Z = lin_svc.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
plt.contourf(xx, yy, Z, cmap=plt.cm.coolwarm, alpha=0.8)
# Afficher aussi les points d'apprentissage
plt.scatter(X_train[:, 0], X_train[:, 1], label="train", edgecolors='k', c=y_train, cmap=plt.cm.coolwarm)
plt.scatter(X_test[:, 0], X_test[:, 1], label="test", marker='*', c=y_test, cmap=plt.cm.coolwarm)
plt.xlabel('Sepal length')
plt.ylabel('Sepal width')
plt.title("LinearSVC")
lin_svc = svm.LinearSVC(C=C).fit(X_train, y_train)
svc = svm.SVC(kernel='linear', C=C).fit(X_train, y_train)
titles = ['SVC with linear kernel', 'LinearSVC (linear kernel)']
fig = plt.figure(figsize=(12, 4.5))
for i, clf in enumerate((svc, lin_svc)):
plt.subplot(1, 2, i + 1)
plt.subplots_adjust(wspace=0.4, hspace=0.4)
Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])
# Utiliser une palette de couleurs
Z = Z.reshape(xx.shape)
plt.contourf(xx, yy, Z, cmap=plt.cm.coolwarm, alpha=0.8)
# Afficher aussi les points d'apprentissage
plt.scatter(X_train[:, 0], X_train[:, 1], label="train", edgecolors='k', c=y_train, cmap=plt.cm.coolwarm)
plt.scatter(X_test[:, 0], X_test[:, 1], label="test", marker='*', c=y_test, cmap=plt.cm.coolwarm)
plt.xlabel('Sepal length')
plt.ylabel('Sepal width')
plt.title(titles[i])
plt.show()
/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/site-packages/sklearn/svm/_classes.py:32: FutureWarning: The default value of `dual` will change from `True` to `'auto'` in 1.5. Set the value of `dual` explicitly to suppress the warning. warnings.warn( /Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/site-packages/sklearn/svm/_base.py:1250: ConvergenceWarning: Liblinear failed to converge, increase the number of iterations. warnings.warn( /Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/site-packages/sklearn/svm/_classes.py:32: FutureWarning: The default value of `dual` will change from `True` to `'auto'` in 1.5. Set the value of `dual` explicitly to suppress the warning. warnings.warn( /Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/site-packages/sklearn/svm/_base.py:1250: ConvergenceWarning: Liblinear failed to converge, increase the number of iterations. warnings.warn(
# Vos données extraites
data = {}
# Charger les données
for i in [1, 2, 3]:
data['X_trainTp{}'.format(i)] = np.loadtxt('data/data_tp{}_app.txt'.format(i), usecols=(1, 2))
data['y_trainTp{}'.format(i)] = np.loadtxt('data/data_tp{}_app.txt'.format(i), usecols=0, dtype=int)
data['X_testTp{}'.format(i)] = np.loadtxt('data/data_tp{}_dec.txt'.format(i), usecols=(1, 2))
data['y_testTp{}'.format(i)] = np.loadtxt('data/data_tp{}_dec.txt'.format(i), usecols=0, dtype=int)
# Choisissez le problème que vous souhaitez visualiser (ici, nous itérons sur tous les problèmes)
current_problem = i
X_train, y_train = data['X_trainTp{}'.format(current_problem)], data['y_trainTp{}'.format(current_problem)]
X_test, y_test = data['X_testTp{}'.format(current_problem)], data['y_testTp{}'.format(current_problem)]
# Paramètre de régularisation
C = 1.0
# Modèle LinearSVC
lin_svc = svm.LinearSVC(C=C)
lin_svc.fit(X_train, y_train)
# Score
print("LinearSVC Score - Problème {}: {}".format(current_problem, lin_svc.score(X_test, y_test)))
# Créer la surface de décision discrétisée
x_min, x_max = X_train[:, 0].min() - 1, X_train[:, 0].max() + 1
y_min, y_max = X_train[:, 1].min() - 1, X_train[:, 1].max() + 1
h = max((x_max - x_min) / 100, (y_max - y_min) / 100)
xx, yy = np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h))
# Surface de décision
Z = lin_svc.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
# Utiliser une palette de couleurs différente (par exemple, viridis)
plt.contourf(xx, yy, Z, cmap=plt.cm.viridis, alpha=0.8)
# Afficher aussi les points d'apprentissage avec des couleurs différentes
plt.scatter(X_train[:, 0], X_train[:, 1], label="train", edgecolors='k', c=y_train, cmap=plt.cm.Paired)
plt.scatter(X_test[:, 0], X_test[:, 1], label="test", marker='*', c=y_test, cmap=plt.cm.Paired)
plt.xlabel('X')
plt.ylabel('Y')
plt.title("LinearSVC - Problème {}".format(current_problem))
plt.legend()
plt.show()
/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/site-packages/sklearn/svm/_classes.py:32: FutureWarning: The default value of `dual` will change from `True` to `'auto'` in 1.5. Set the value of `dual` explicitly to suppress the warning. warnings.warn( /Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/site-packages/sklearn/svm/_base.py:1250: ConvergenceWarning: Liblinear failed to converge, increase the number of iterations. warnings.warn(
LinearSVC Score - Problème 1: 0.994
/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/site-packages/sklearn/svm/_classes.py:32: FutureWarning: The default value of `dual` will change from `True` to `'auto'` in 1.5. Set the value of `dual` explicitly to suppress the warning. warnings.warn( /Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/site-packages/sklearn/svm/_base.py:1250: ConvergenceWarning: Liblinear failed to converge, increase the number of iterations. warnings.warn(
LinearSVC Score - Problème 2: 0.934
/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/site-packages/sklearn/svm/_classes.py:32: FutureWarning: The default value of `dual` will change from `True` to `'auto'` in 1.5. Set the value of `dual` explicitly to suppress the warning. warnings.warn( /Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/site-packages/sklearn/svm/_base.py:1250: ConvergenceWarning: Liblinear failed to converge, increase the number of iterations. warnings.warn(
LinearSVC Score - Problème 3: 0.712