This commit is contained in:
2025-01-28 15:54:25 +01:00
parent 9f681902db
commit 07d489824e
3 changed files with 1721 additions and 0 deletions

View File

@@ -0,0 +1,6 @@
{
"cells": [],
"metadata": {},
"nbformat": 4,
"nbformat_minor": 5
}

1325
TP05/Untitled.ipynb Normal file

File diff suppressed because one or more lines are too long

390
TP05/tp05.py Normal file
View File

@@ -0,0 +1,390 @@
"""
Projet de Machine Learning : Prédiction de Maladies Cardiaques (Version corrigée)
Dataset : UCI Heart Disease Dataset
Objectif : Comparer deux architectures de réseaux de neurones pour la prédiction de maladies cardiaques
"""
import pandas as pd
import numpy as np
import urllib.request
import ssl
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Dropout, BatchNormalization
from tensorflow.keras.optimizers import Adam
from tensorflow.keras.callbacks import EarlyStopping
import matplotlib.pyplot as plt
# 1. Chargement des données avec gestion du SSL
def load_data():
try:
# Créer un contexte SSL non-vérifié (à utiliser avec précaution)
ssl._create_default_https_context = ssl._create_unverified_context
# URL du dataset
url = "https://archive.ics.uci.edu/ml/machine-learning-databases/heart-disease/processed.cleveland.data"
# Définir les noms des colonnes
columns = ['age', 'sex', 'cp', 'trestbps', 'chol', 'fbs', 'restecg', 'thalach',
'exang', 'oldpeak', 'slope', 'ca', 'thal', 'target']
print("Téléchargement des données...")
# Télécharger directement dans un DataFrame
data = pd.read_csv(url, names=columns)
# En cas d'erreur, utiliser un dataset de démonstration
if data.empty:
raise Exception("Le dataset est vide")
except Exception as e:
print(f"Erreur lors du téléchargement des données: {e}")
print("Utilisation d'un dataset de démonstration...")
# Créer un petit dataset de démonstration
np.random.seed(42)
n_samples = 300
data = pd.DataFrame({
'age': np.random.normal(55, 10, n_samples),
'sex': np.random.binomial(1, 0.5, n_samples),
'cp': np.random.randint(0, 4, n_samples),
'trestbps': np.random.normal(130, 20, n_samples),
'chol': np.random.normal(240, 40, n_samples),
'fbs': np.random.binomial(1, 0.2, n_samples),
'restecg': np.random.randint(0, 3, n_samples),
'thalach': np.random.normal(150, 20, n_samples),
'exang': np.random.binomial(1, 0.3, n_samples),
'oldpeak': np.random.normal(1, 1, n_samples),
'slope': np.random.randint(0, 3, n_samples),
'ca': np.random.randint(0, 4, n_samples),
'thal': np.random.randint(0, 3, n_samples),
'target': np.random.binomial(1, 0.4, n_samples)
})
# Nettoyer les données
data = data.replace('?', np.nan)
data = data.dropna()
# Convertir les colonnes en nombres
for column in data.columns:
data[column] = pd.to_numeric(data[column])
# Binariser la target (0 pour pas de maladie, 1 pour maladie)
data['target'] = (data['target'] > 0).astype(int)
return data
# 2. Prétraitement des données
def preprocess_data(data):
# Séparer features et target
X = data.drop('target', axis=1)
y = data['target']
# Split train/test
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# Standardisation
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)
return X_train_scaled, X_test_scaled, y_train, y_test
# 3. Premier modèle : Réseau dense classique
def create_model_1(input_shape):
model = Sequential([
Dense(64, activation='relu', input_shape=input_shape),
BatchNormalization(),
Dense(32, activation='relu'),
Dropout(0.3),
Dense(16, activation='relu'),
Dense(1, activation='sigmoid')
])
model.compile(optimizer=Adam(learning_rate=0.001),
loss='binary_crossentropy',
metrics=['accuracy'])
return model
# 4. Second modèle : Réseau plus profond avec régularisation plus forte
def create_model_2(input_shape):
model = Sequential([
Dense(128, activation='relu', input_shape=input_shape),
BatchNormalization(),
Dropout(0.3),
Dense(64, activation='relu'),
BatchNormalization(),
Dropout(0.3),
Dense(32, activation='relu'),
BatchNormalization(),
Dense(16, activation='relu'),
Dense(1, activation='sigmoid')
])
model.compile(optimizer=Adam(learning_rate=0.001),
loss='binary_crossentropy',
metrics=['accuracy'])
return model
# 5. Fonction d'entraînement et d'évaluation
def train_and_evaluate(model, X_train, X_test, y_train, y_test, model_name):
# Early stopping pour éviter le surapprentissage
early_stopping = EarlyStopping(
monitor='val_loss',
patience=10,
restore_best_weights=True,
verbose=1
)
# Entraînement
history = model.fit(
X_train, y_train,
validation_split=0.2,
epochs=50, # Réduit pour la démonstration
batch_size=32,
callbacks=[early_stopping],
verbose=1
)
# Évaluation
test_loss, test_accuracy = model.evaluate(X_test, y_test, verbose=0)
print(f"\n{model_name} - Test Accuracy: {test_accuracy:.4f}")
return history
# 6. Visualisation des résultats
def plot_training_history(history1, history2):
plt.figure(figsize=(12, 4))
# Plot accuracy
plt.subplot(1, 2, 1)
plt.plot(history1.history['accuracy'], label='Model 1 accuracy')
plt.plot(history1.history['val_accuracy'], label='Model 1 val accuracy')
plt.plot(history2.history['accuracy'], label='Model 2 accuracy')
plt.plot(history2.history['val_accuracy'], label='Model 2 val accuracy')
plt.title('Model Accuracy')
plt.xlabel('Epoch')
plt.ylabel('Accuracy')
plt.legend()
# Plot loss
plt.subplot(1, 2, 2)
plt.plot(history1.history['loss'], label='Model 1 loss')
plt.plot(history1.history['val_loss'], label='Model 1 val loss')
plt.plot(history2.history['loss'], label='Model 2 loss')
plt.plot(history2.history['val_loss'], label='Model 2 val loss')
plt.title('Model Loss')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.legend()
plt.tight_layout()
plt.show()
# 7. Programme principal
def main():
print("Loading data...")
data = load_data()
print("Data shape:", data.shape)
print("\nPreprocessing data...")
X_train, X_test, y_train, y_test = preprocess_data(data)
input_shape = (X_train.shape[1],)
print("\nTraining Model 1...")
model1 = create_model_1(input_shape)
history1 = train_and_evaluate(model1, X_train, X_test, y_train, y_test, "Model 1")
print("\nTraining Model 2...")
model2 = create_model_2(input_shape)
history2 = train_and_evaluate(model2, X_train, X_test, y_train, y_test, "Model 2")
print("\nPlotting results...")
plot_training_history(history1, history2)
if __name__ == "__main__":
main()
'''
Modèle 1 : Réseau Dense Classique
- C'est une architecture relativement simple et légère avec 4 couches :
1. Première couche : 64 neurones avec activation ReLU
- Cette couche initiale capture les patterns de base dans les données
- Suivie d'une normalisation par lots (BatchNormalization) pour stabiliser l'apprentissage
2. Deuxième couche : 32 neurones avec activation ReLU
- Suivie d'un Dropout de 30% pour éviter le surapprentissage
3. Troisième couche : 16 neurones avec activation ReLU
- Réduit progressivement la dimensionnalité
4. Couche de sortie : 1 neurone avec activation sigmoid
- Pour la prédiction binaire (malade/non malade)
Modèle 2 : Réseau Plus Profond
- C'est une architecture plus complexe avec 5 couches et plus de régularisation :
1. Première couche : 128 neurones avec activation ReLU
- Commence avec plus de neurones pour capturer des patterns plus complexes
- Suivie de BatchNormalization et Dropout 30%
2. Deuxième couche : 64 neurones avec activation ReLU
- Également suivie de BatchNormalization et Dropout
3. Troisième couche : 32 neurones avec activation ReLU
- Avec BatchNormalization
4. Quatrième couche : 16 neurones avec activation ReLU
5. Couche de sortie : 1 neurone avec activation sigmoid
Les principales différences sont :
1. Complexité : Le modèle 2 a plus de paramètres et de couches
2. Régularisation : Le modèle 2 utilise plus de BatchNormalization et de Dropout
3. Capacité d'apprentissage : Le modèle 2 peut capturer des relations plus complexes dans les données
L'idée est de comparer :
- Une approche simple qui pourrait suffire pour ce problème médical relativement simple
- Une approche plus complexe qui pourrait potentiellement capturer des patterns plus subtils
Les deux modèles utilisent le même optimiseur (Adam) avec le même learning rate (0.001) pour une comparaison équitable.
Cette configuration permet d'observer si la complexité supplémentaire du deuxième modèle apporte réellement un avantage en termes de performances, ou si le modèle plus simple est suffisant.
- ReLU (Rectified Linear Unit) est une fonction d'activation très populaire en deep learning : ReLu (x) = max (0,x)
- Le Dropout est une technique de régularisation cruciale en deep learning. Voici une explication détaillée :
Principe de base :
Pendant l'entraînement, à chaque itération
Désactive aléatoirement un certain pourcentage de neurones
Ces neurones sont temporairement "éteints" avec toutes leurs connexions
Le pourcentage est défini par le paramètre de dropout (ex: 0.3 = 30% des neurones)
- La BatchNormalization (ou normalisation par lots) est une technique très importante en deep learning. Voici une explication détaillée :
Principe fondamental :
Normalise les activations d'une couche pour chaque batch
Maintient la moyenne proche de 0 et l'écart-type proche de 1
S'applique avant la fonction d'activation
'''
'''
## Exercice 1 :
adapter le programme sur les données suivantes :
https://archive.ics.uci.edu/ml/machine-learning-databases/breast-cancer-wisconsin/wdbc.data
## Exercice 2 :
On vous demande d'implémenter 2 autres modèles en suivant le schéma du programme donné. Sur les 2 data-set.
L'objectif est de rendre un rapport explicatif complet sur au moins un des modèles ; le code doit être commenté et des tests (changement de paramètres : itération, taux, couches réseaux) doivent être fait.
### Premier Modèle : Random Forest Classifier
Ce modèle est particulièrement intéressant car il offre :
- Une excellente performance sur les données médicales
- Une interprétabilité des résultats
- Une facilité relative d'implémentation
Voici un exemple de structure pour l'implémentation :
```python
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import GridSearchCV
def create_model_rf(X_train, y_train):
# Création du modèle avec des hyperparamètres de base
rf_model = RandomForestClassifier(
n_estimators=100,
max_depth=10,
random_state=42
)
# Définition des paramètres à optimiser
param_grid = {
'n_estimators': [50, 100, 200],
'max_depth': [5, 10, 15],
'min_samples_split': [2, 5, 10]
}
# Recherche des meilleurs paramètres
grid_search = GridSearchCV(
rf_model,
param_grid,
cv=5,
scoring='accuracy',
n_jobs=-1
)
# Entraînement avec recherche des meilleurs paramètres
grid_search.fit(X_train, y_train)
return grid_search.best_estimator_
```
### Deuxième Modèle : XGBoost
XGBoost est un algorithme de boosting très performant qui permet souvent d'obtenir d'excellents résultats. Voici une structure d'implémentation :
```python
import xgboost as xgb
from sklearn.model_selection import cross_val_score
def create_model_xgb(X_train, y_train):
# Création du modèle avec des paramètres de base
xgb_model = xgb.XGBClassifier(
learning_rate=0.1,
n_estimators=100,
max_depth=5,
random_state=42
)
# Paramètres à optimiser
param_grid = {
'learning_rate': [0.01, 0.1, 0.3],
'n_estimators': [50, 100, 200],
'max_depth': [3, 5, 7]
}
# Optimisation des hyperparamètres
grid_search = GridSearchCV(
xgb_model,
param_grid,
cv=5,
scoring='accuracy',
n_jobs=-1
)
grid_search.fit(X_train, y_train)
return grid_search.best_estimator_
```
Pour faciliter l'implémentation, voici les points essentiels à comprendre :
Pour le Random Forest :
- C'est un ensemble d'arbres de décision
- Chaque arbre est entraîné sur un sous-ensemble aléatoire des données
- La prédiction finale est obtenue par vote majoritaire des arbres
- Les paramètres clés sont le nombre d'arbres (n_estimators) et la profondeur maximale (max_depth)
Pour XGBoost :
- C'est un algorithme de boosting qui construit les arbres séquentiellement
- Chaque nouvel arbre corrige les erreurs des arbres précédents
- Le learning_rate contrôle la contribution de chaque arbre
- La profondeur des arbres (max_depth) limite la complexité du modèle
Pour l'évaluation des modèles, on peut réutiliser les fonctions de visualisation existantes en les adaptant légèrement. Par exemple :
```python
def plot_model_comparison(models_results):
plt.figure(figsize=(10, 6))
for model_name, scores in models_results.items():
plt.plot(scores['val_accuracy'], label=f'{model_name} validation accuracy')
plt.title('Model Comparison')
plt.xlabel('Iteration')
plt.ylabel('Accuracy')
plt.legend()
plt.show()
```
'''