Skip to content
Snippets Groups Projects
Commit 60993a46 authored by FERRAT Samy's avatar FERRAT Samy
Browse files

commit

parent d6b4f840
No related branches found
No related tags found
No related merge requests found
%% Cell type:markdown id: tags:
 
<center>
<h1 style="color:green">
<b>
<u> PROJECT </u>
</b>
</h1>
</center>
 
%% Cell type:code id: tags:
 
``` python
import pandas as pd
import missingno as msno
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from src.data_processing.load_data import load_data
from src.data_processing.preprocessing import rename_data
from src.data_processing.preprocessing import cat_to_quant
from src.data_processing.preprocessing import delete_feature
from src.data_processing.preprocessing import encode_and_bind
from src.data_processing.preprocessing import impute_mean
from src.figures.figures import plot_area_price_relationship, plot_correlation_matrix, plot_air_conditioning_presence, plot_bedrooms_distribution, plot_price_distribution
from src.data_science.data import split_data
from sklearn.metrics import r2_score
from sklearn.metrics import mean_squared_error
from sklearn.linear_model import LinearRegression
from sklearn.ensemble import RandomForestRegressor
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import RandomizedSearchCV
from sklearn.model_selection import GridSearchCV
from config.config import TEST_RATIO, SEED, SIZE_TRAIN
```
 
%% Cell type:code id: tags:
 
``` python
print(TEST_RATIO, SEED)
```
 
%% Output
 
0.2 5
 
%% Cell type:markdown id: tags:
 
# EDA
 
%% Cell type:markdown id: tags:
 
## Chargement et prétraitement des données
 
%% Cell type:code id: tags:
 
``` python
df = load_data('data/raw/house_prices.csv')
```
 
%% Cell type:code id: tags:
 
``` python
df.head()
```
 
%% Output
 
price AreA bedrooms BATHROOMS stories mainroad guestroom \
0 4543000.0 4990.0 4.0 2.0 2.0 yes yes
1 8080940.0 7000.0 3.0 2.0 4.0 yes no
2 8750000.0 4321.0 3.0 2.0 2.0 yes no
3 1890000.0 1700.0 3.0 1.0 2.0 yes no
4 12215000.0 7500.0 4.0 2.0 2.0 yes no
price AreA bedrooms ... prefarea furnishing STATUS houSeaGe
0 4543000.0 4990.0 4.0 ... yes furnished 15.0
1 8080940.0 7000.0 3.0 ... no FURNISHED 11.0
2 8750000.0 4321.0 3.0 ... no FURNISHED NaN
3 1890000.0 1700.0 3.0 ... no unfurnished NaN
4 12215000.0 7500.0 4.0 ... yes furnished NaN
basement hotwaterheating air conditioning parking prefarea \
0 yes no no 0.0 yes
1 no no yes 2.0 no
2 yes yes no 2.0 no
3 no no no 0.0 no
4 yes no yes 3.0 yes
furnishing STATUS houSeaGe
0 furnished 15.0
1 FURNISHED 11.0
2 FURNISHED NaN
3 unfurnished NaN
4 furnished NaN
[5 rows x 14 columns]
 
%% Cell type:code id: tags:
 
``` python
df = rename_data(df) # On renomme correctement les noms de variable
```
 
%% Cell type:code id: tags:
 
``` python
df = cat_to_quant(df) # On transforme les données catégorielles en données quantitatives
```
 
%% Output
 
c:\Users\samys\OneDrive\Bureau\last_test\projet-python-m2-ds-2024\src\data_processing\preprocessing.py:30: FutureWarning: Downcasting behavior in `replace` is deprecated and will be removed in a future version. To retain the old behavior, explicitly call `result.infer_objects(copy=False)`. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`
c:\Users\samys\OneDrive\Bureau\verylasttest\projet-python-m2-ds-2024\src\data_processing\preprocessing.py:30: FutureWarning: Downcasting behavior in `replace` is deprecated and will be removed in a future version. To retain the old behavior, explicitly call `result.infer_objects(copy=False)`. To opt-in to the future behavior, set `pd.set_option('future.no_silent_downcasting', True)`
data=data.replace({'yes': 1, 'no': 0})
 
%% Cell type:markdown id: tags:
 
On transforme la variable 'furnishing_status' en variable numérique
 
%% Cell type:code id: tags:
 
``` python
df=encode_and_bind(df,'furnishing_status')
```
 
%% Cell type:markdown id: tags:
 
Visualisons les données manquantes dans le jeu de données
 
%% Cell type:code id: tags:
 
``` python
missing = df.isnull()
 
plt.figure(figsize=(6,4))
sns.heatmap(missing, cbar=False,yticklabels=False)
plt.title('Visualisation de données manquantes')
plt.show()
```
 
%% Output
 
 
%% Cell type:markdown id: tags:
 
On décide de virer la colonne 'houseage' car elle contient quasiment exclusivement des données manquantes et d'imputer le reste des variables avec leurs moyennes respectives.
 
%% Cell type:code id: tags:
 
``` python
df = delete_feature(df,'houseage') #Suppresion de la variable 'housage'
df = impute_mean(df)
```
 
%% Cell type:markdown id: tags:
 
Voici un aperçu notre jeu de données après le prétraitement des données :
 
%% Cell type:code id: tags:
 
``` python
df.head()
```
 
%% Output
 
price area bedrooms bathrooms stories mainroad guestroom \
0 4543000 4990 4 2 2 1 1
1 8080940 7000 3 2 4 1 0
2 8750000 4321 3 2 2 1 0
3 1890000 1700 3 1 2 1 0
4 12215000 7500 4 2 2 1 0
basement hotwaterheating air_conditioning parking prefarea furnished \
0 1 0 0 0 1 1
1 0 0 1 2 0 1
2 1 1 0 2 0 1
3 0 0 0 0 0 0
4 1 0 1 3 1 1
price area bedrooms ... prefarea furnished semi-furnished
0 4543000 4990 4 ... 1 1 0
1 8080940 7000 3 ... 0 1 0
2 8750000 4321 3 ... 0 1 0
3 1890000 1700 3 ... 0 0 0
4 12215000 7500 4 ... 1 1 0
semi-furnished
0 0
1 0
2 0
3 0
4 0
[5 rows x 14 columns]
 
%% Cell type:markdown id: tags:
 
## Exploration des données
 
%% Cell type:code id: tags:
 
``` python
# histogramme de la distribution des prix de vente
plot_price_distribution(df)
 
 
#diagramme de presence ou non de la climatisation
plot_air_conditioning_presence(df)
 
 
# Diagramme en barres pour une variable catégorielle (Nombre de chambres)
plot_bedrooms_distribution(df)
 
```
 
%% Output
 
 
 
 
%% Cell type:code id: tags:
 
``` python
# Scatter plot pour les relations entre variables numériques (ex. SalePrice et LotArea)
plot_area_price_relationship(df)
 
 
 
# Heatmap pour visualiser la corrélation entre les variables numériques
plot_correlation_matrix(df)
 
```
 
%% Output
 
 
 
%% Cell type:markdown id: tags:
 
On remarque que la plus forte corrélation est entre la variable 'price' et 'bathrooms', ce qui pouvait etre attendu etant donné qu'avoir plusieurs salles de bain est réservé aux maisons assez luxueuses, la seconde plus forte corrélation est entre la variable 'price' et 'area' ce qui est aussi prévisible.
 
%% Cell type:markdown id: tags:
 
# Validation croisée
 
%% Cell type:code id: tags:
 
``` python
X_train, y_train, X_test, y_test = split_data(df,test_ratio=TEST_RATIO,random_seed=SEED,target_column='price')
```
 
%% Cell type:code id: tags:
 
``` python
#normalisation des données
 
normalization = StandardScaler()
normalization_y = StandardScaler()
 
#restructuration des données de sorte à ce que la normalisation avec sklearn puisse etre fait
y_train = np.array(y_train).reshape(-1,1)
y_test = np.array(y_test).reshape(-1,1)
 
normalization.fit(X_train)
normalization_y.fit(y_train)
 
#Normalisation des covariables
X_train = normalization.transform(X_train)
X_test = normalization.transform(X_test)
 
 
 
#Normalisation de la variable cible
y_train = normalization_y.transform(y_train)
y_test = normalization_y.transform(y_test)
```
 
%% Cell type:code id: tags:
 
``` python
#retransformation de y_train et y_test en 1D
 
y_train = y_train.ravel()
y_test = y_test.ravel()
```
 
%% Cell type:markdown id: tags:
 
# Machine Learning
 
%% Cell type:markdown id: tags:
 
## Entrainement sur la variable bedrooms
 
%% Cell type:code id: tags:
 
``` python
list_error = []
size_train = SIZE_TRAIN #différentes tailles d'évaluation du modèle
 
# On réalise une boucle sur différentes tailles de l'ensemble d'entraînement
for n in size_train:
# Sélectionner l'ensemble d'entraînement et de test correspondant
X_train_subset = X_train[:,1][:n]
y_train_subset = y_train[:n]
 
# entrainement du modele
lin_reg_baseline = LinearRegression()
lin_reg_baseline.fit(X_train_subset.reshape(-1,1),y_train_subset)
 
#calcul de la prédiction
y_pred = lin_reg_baseline.predict(X_test[:,1].reshape(-1,1))
y_pred_bed = lin_reg_baseline.predict(X_test[:,1].reshape(-1,1))
 
# calcul de l'erreur R2
error_mse = np.mean((y_test-y_pred)**2)
# calcul du MSE
error_mse = mean_squared_error(y_test,y_pred_bed)
list_error.append(error_mse)
```
 
%% Cell type:code id: tags:
 
``` python
# Affichage du graphique représentant l'erreur en fonction de la taille de l'ensemble d'entraînement
plt.plot(size_train, list_error, marker='o')
plt.xlabel("Taille de l'ensemble d'entraînement")
plt.ylabel("Erreur (MSE)")
plt.title("Erreur en fonction de la taille de l'ensemble d'entraînement")
 
plt.show()
```
 
%% Output
 
 
%% Cell type:markdown id: tags:
 
On voit un optimum de la taille de l'ensemble d'entrainement pourn n=648 (l'ensemble du jeu d'entrainements), on remarque aussi une que l'erreur MSE est plus grande pour n=250 et n=450 que pour n=100 et n=50, ce qui montre qu'un ensemble d'entrainement plus grand n'implique pas systématiquement de meilleures performances, meme si ici cela pourrait etre lié à la simplicité du modèle
 
%% Cell type:markdown id: tags:
 
## Entrainement d'une regression linéaire sur toutes les données
 
%% Cell type:code id: tags:
 
``` python
list_error=[]
# on réalise une boucle sur différentes tailles de l'ensemble d'entrainement
for n in size_train:
 
X_train_subset = X_train[:n]
y_train_subset = y_train[:n]
 
# entrainement du modele
lin_reg = LinearRegression()
lin_reg.fit(X_train_subset,y_train_subset)
 
#calcul de la prédiction
y_pred=lin_reg.predict(X_test)
 
# calcul de l'erreur R2
error_mse=np.mean((y_test-y_pred)**2)
print(r2_score(y_test,y_pred))
# calcul du MSE
error_mse=mean_squared_error(y_test,y_pred)
list_error.append(error_mse)
```
 
%% Output
-0.18908813220600074
0.49828257362511363
0.6595360217499793
0.6738827057529093
0.6710848125168165
0.6714672798459871
%% Cell type:code id: tags:
 
``` python
# affichage du graphique représentant l'erreur en fonction de la taille de l'ensemble d'entrainement
 
plt.plot(size_train, list_error, marker='o')
 
plt.xlabel("Taille de l'ensemble d'entraînement")
plt.ylabel("Erreur")
plt.title("Erreur en fonction de la taille de l'ensemble d'entraînement")
 
 
plt.show()
```
 
%% Output
 
 
%% Cell type:markdown id: tags:
 
L'ajout de données améliore la performance du modèle cependant on constate une très faible amélioration du score à partir de n=100, mais qui est très forte entre n=10 et n=100
L'ajout de données améliore la performance du modèle cependant on constate une très faible amélioration du score à partir de n=100, mais qui est très forte entre n=10 et n=100, cet exemple met en évidence l'importance de la taille de l'ensemble d'entrainement pour avoir de meilleurs résultats.
 
%% Cell type:markdown id: tags:
 
## Forets aléatoires
 
%% Cell type:code id: tags:
 
``` python
n_estimators_list = [5,10,20,50]
max_depth_list = [5, 15 ,22,30, 40,50,60]
 
# Stocker les résultats
results = {}
 
for n_estimators in n_estimators_list:
test_scores = []
 
for max_depth in max_depth_list:
# Définir le modèle Random Forest
rf = RandomForestRegressor(n_estimators=n_estimators, max_depth=max_depth, random_state=42)
 
# Entraînement du modèle
rf.fit(X_train, y_train)
 
# Prédictions
y_pred = rf.predict(X_test)
y_pred_forest = rf.predict(X_test)
 
# Calcul de l'erreur
error_mse_forest = np.mean((y_test-y_pred)**2)
error_mse_forest = mean_squared_error(y_test,y_pred_forest)
 
test_scores.append(error_mse_forest)
 
# Sauvegarder les résultats pour chaque n_estimators
results[n_estimators] = {
"max_depth": max_depth_list,
"test_scores": test_scores
}
 
# Affichage des graphes
plt.figure(figsize=(15, 10))
for i, n_estimators in enumerate(n_estimators_list):
plt.subplot(3, 2, i + 1)
plt.plot(results[n_estimators]["max_depth"], results[n_estimators]["test_scores"], label="Test")
plt.title(f"n_estimators = {n_estimators}")
plt.xlabel("max_depth")
plt.ylabel("MSE")
plt.legend()
plt.tight_layout()
 
plt.show()
```
 
%% Output
 
 
%% Cell type:markdown id: tags:
 
On voit que la meilleure MSE a lieu pour un nombre d'estimateurs à 50 et une maximum de profondeur de 15 (pour plus de profondeur ça stagne), on constate aussi qu'on a une meilleure MSE que pour la régression linéaire
 
%% Cell type:code id: tags:
 
``` python
rf = RandomForestRegressor(n_estimators=50, max_depth=15, random_state=42)
rf.fit(X_train,y_train)
```
 
%% Output
 
RandomForestRegressor(max_depth=15, n_estimators=50, random_state=42)
 
%% Cell type:code id: tags:
``` python
r2_score(y_test,rf.predict(X_test))
```
%% Output
0.8074574314651273
%% Cell type:markdown id: tags:
 
## Features Importances
 
%% Cell type:markdown id: tags:
 
### Régression linéaire
 
%% Cell type:code id: tags:
 
``` python
# Extraction des coefficients
coefficients = lin_reg.coef_
 
coef = pd.DataFrame()
coef['Coefficient'] = coefficients
coef['Columns']=df.iloc[:,1:].columns
print(coef)
```
 
%% Output
 
Coefficient Columns
0 0.251262 area
1 0.063651 bedrooms
2 0.306408 bathrooms
3 0.152747 stories
4 0.085228 mainroad
5 0.063935 guestroom
6 0.063827 basement
7 0.125000 hotwaterheating
8 0.224648 air_conditioning
9 0.137781 parking
10 0.134494 prefarea
11 0.068656 furnished
12 0.079305 semi-furnished
 
%% Cell type:code id: tags:
 
``` python
plt.barh(range(len(coefficients)), coefficients)
plt.yticks(range(len(coefficients)), df.iloc[:,1:].columns)
plt.xlabel('Importance de la caractéristique')
plt.ylabel('Caractéristiques')
plt.show()
```
 
%% Output
 
 
%% Cell type:markdown id: tags:
 
Etant donné que le jeu de données a été centré réduit nous pouvons directement analysé l'importance de chaque feature par son coefficient associé. On constate donc que les coefficients les plus forts sont associés d'abord à la variable 'bathrooms' avec un coefficient associé de 0.36 puis à la variable 'area' avec un coefficient associé de 0.244, ces résultats concordent avec notre visualisation des corrélations entre variables.
 
%% Cell type:markdown id: tags:
 
### Forets aléatoires
 
%% Cell type:code id: tags:
 
``` python
coefficients_rf = rf.feature_importances_
 
coef_rf = pd.DataFrame()
coef_rf['Coefficient'] = coefficients_rf
coef_rf['Columns'] = df.iloc[:,1:].columns
print(coef_rf)
```
 
%% Output
 
Coefficient Columns
0 0.364237 area
1 0.025185 bedrooms
2 0.304803 bathrooms
3 0.049687 stories
4 0.009976 mainroad
5 0.020051 guestroom
6 0.021538 basement
7 0.028398 hotwaterheating
8 0.048936 air_conditioning
9 0.054310 parking
10 0.031695 prefarea
11 0.020924 furnished
12 0.020259 semi-furnished
 
%% Cell type:code id: tags:
 
``` python
plt.barh(range(len(coefficients_rf)), coefficients_rf)
plt.yticks(range(len(coefficients_rf)), df.iloc[:,1:].columns)
plt.xlabel('Importance de la caractéristique')
plt.ylabel('Caractéristiques')
plt.show()
```
 
%% Output
 
 
%% Cell type:markdown id: tags:
 
Ici encore plus que pour la régression linéaire les 2 variables les plus importantes dans le modèle sont 'bathrooms' et 'area'
 
%% Cell type:markdown id: tags:
 
## Bonus: RandomizedSearchCV and GridSearchCV
 
%% Cell type:markdown id: tags:
 
GridSearchCV fait de la validation croisée sur toutes les combinaisons de paramètres qu'on lui fournit, RandomSearchCV quant à elle fait de la validation croisée avec un nombre de combinaisons spécifiées par la paramètre "n_iter" de manière aléatoire.
##### Avantages et inconvénients :
- Testant toutes les combinaisons de paramètres GridSearchCV va fournir la meilleure combinaison possible de paramètre mais est plus couteuse computationnellement que RandomSearchCV inversement RandomSearchCV ne va pas forcément sortir la combinaison optimale mais la méthode est moins couteuse, en pratique pour des modèles complexes et sur de gros jeu de données RandomSearchCV va etre plus utilisé.
 
%% Cell type:code id: tags:
 
``` python
 
# Hyperparamètres à explorer
param_distributions = {
'n_estimators': n_estimators_list,
'max_depth': max_depth_list
}
 
rf = RandomForestRegressor(random_state=42)
 
 
random_search = RandomizedSearchCV(
estimator=rf,
param_distributions=param_distributions,
n_iter=8, # Nombre de combinaisons à tester
scoring='neg_mean_squared_error',
cv=5,
random_state=42
)
 
random_search.fit(X_train, y_train)
 
 
best_params_random = random_search.best_params_
best_model_random = random_search.best_estimator_
 
y_pred_random = best_model_random.predict(X_test)
 
# Calcul du R2 sur l'ensemble de test
r2_test_random = np.mean((y_test - y_pred_random)**2)
# Calcul de la MSE sur l'ensemble de test
mse_test_random = mean_squared_error(y_test,y_pred_random)
 
print("Meilleurs hyperparamètres (RandomizedSearchCV) :", best_params_random)
print("Score R2 sur l'ensemble de test :", r2_test_random)
print("Score MSE sur l'ensemble de test :", mse_test_random)
```
 
%% Output
 
Meilleurs hyperparamètres (RandomizedSearchCV) : {'n_estimators': 20, 'max_depth': 50}
Score R2 sur l'ensemble de test : 0.17109802066519297
c:\Users\samys\anaconda\envs\jpp\Lib\site-packages\numpy\ma\core.py:2881: RuntimeWarning: invalid value encountered in cast
_data = np.array(data, dtype=dtype, copy=copy,
Score MSE sur l'ensemble de test : 0.17109802066519297
 
%% Cell type:code id: tags:
 
``` python
from sklearn.model_selection import GridSearchCV
 
# Définir la grille des hyperparamètres
param_grid = {
'n_estimators': n_estimators_list,
'max_depth': max_depth_list
}
 
# Définir le modèle Random Forest
rf = RandomForestRegressor()
 
grid_search = GridSearchCV(
estimator=rf,
param_grid=param_grid,
scoring='neg_mean_squared_error',
cv=5
)
 
grid_search.fit(X_train, y_train)
 
 
best_params_grid = grid_search.best_params_
best_model_grid = grid_search.best_estimator_
 
y_pred_grid = best_model_grid.predict(X_test)
 
# Calcul du R2 sur l'ensemble de test
r2_test_grid = np.mean((y_test - y_pred_grid)**2)
# Calcul de la MSE sur l'ensemble de test
mse_test_grid = mean_squared_error(y_test,y_pred_grid)
 
print("Meilleurs hyperparamètres (GridSearchCV) :", best_params_grid)
print("Score R2 sur l'ensemble de test :", r2_test_grid)
print("Score MSE sur l'ensemble de test :", mse_test_grid)
```
 
%% Output
 
Meilleurs hyperparamètres (GridSearchCV) : {'max_depth': 22, 'n_estimators': 20}
Score R2 sur l'ensemble de test : 0.17383407975848472
c:\Users\samys\anaconda\envs\jpp\Lib\site-packages\numpy\ma\core.py:2881: RuntimeWarning: invalid value encountered in cast
_data = np.array(data, dtype=dtype, copy=copy,
Score MSE sur l'ensemble de test : 0.17383407975848472
 
%% Cell type:markdown id: tags:
 
On constate qu'on a pas les memes meilleurs hyperparamètres entre GridSearchCV et RandomSearchCV, et on obtient une meilleure MSE avec GridSearchCV sur l'ensemble de test ce qui est prévisible car GridSearchCV explore toutes les combinaisons d'hyperparamètres possibles contrairement à RandomSearchCV.
On constate qu'on a pas les memes hyperparamètres optimaux entre GridSearchCV et RandomSearchCV ce qui est normal, et on obtient une meilleure MSE avec RandomSearchCV sur l'ensemble de test, ce qui est possible car les meilleurs hyperparamètres sur l'ensemble d'entrainement ne sont pas forcément meilleurs sur l'ensemble de test
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment