Projet final : House price

Par Aouatif BOZAZ

1. Lecture du data :

Pour commencer le traitement de la base données, on a besoin d'importer les librairies qu'on utilisera par la suite, ainsi d'uploader dataframes train et test du site kaggle sous les noms : 'df' et 'df_valid'.

In [1]:
#Importation des librairies :
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
import seaborn as sns
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier, export_graphviz
from sklearn.metrics import confusion_matrix, classification_report, mean_squared_error
from sklearn.preprocessing import LabelEncoder
from sklearn.datasets import load_iris
from IPython.display import Image
from sklearn.ensemble import RandomForestRegressor
from sklearn.pipeline import Pipeline
from sklearn import linear_model
from sklearn.metrics import r2_score
from sklearn.linear_model import Ridge, RidgeCV, ElasticNet, LassoCV, LassoLarsCV
In [2]:
#Importer data train : 
df = pd.read_csv ("C:/Users/aouatif.bozaz/Downloads/train.csv", sep=',')
In [3]:
#Importer data test de la validation des modèles: 
df_Valid = pd.read_csv ("C:/Users/aouatif.bozaz/Downloads/test.csv", sep=',')
In [4]:
#Information sur dataframes : 
df.shape
Out[4]:
(1460, 81)
In [5]:
df_Valid.shape
Out[5]:
(1459, 80)

On a sur train 81 variables dont 'SalePrice' est la variable à prédire, et qui est la variable supprimé du dataframe df_Valid. Sur train on a 1460 observations.

Maintenant, on a besoin d'analyser les variables et les observations pour détecter les valeurs manquantes et aberrantes. On commence par les variables nuériques : remplacer les valeurs nulles par la moyenne de la variable. Ensuite, les variables catégoriques : il faut les encoder pour les intégrer dans les modèles qu'on proposera.

2. Clean dataframes :

In [6]:
df.isnull().sum().sort_values(ascending=False).head(20)
Out[6]:
PoolQC          1453
MiscFeature     1406
Alley           1369
Fence           1179
FireplaceQu      690
LotFrontage      259
GarageCond        81
GarageType        81
GarageYrBlt       81
GarageFinish      81
GarageQual        81
BsmtExposure      38
BsmtFinType2      38
BsmtFinType1      37
BsmtCond          37
BsmtQual          37
MasVnrArea         8
MasVnrType         8
Electrical         1
Utilities          0
dtype: int64
In [7]:
#Ploter les variables ayant des valeurs manquantes sur dataframe de validation : 
sns.heatmap(df_Valid.isnull(), yticklabels = False, cbar= False)
Out[7]:
<matplotlib.axes._subplots.AxesSubplot at 0x1edc2812be0>

On constate que les variables suivantes: Alley, PoolArea, Fence, MiscFeature et FireplaceQu contiennent un grand nombre de valeurs manquantes, or si on analyse la varible, les lignes avec NA donne une information sur la disponibilté de la variable; par exemple, NA dans la colonne de la variable 'alley' désigne que il n'y a pas d'accès par ruelle à la maison, qui demeure une information très importante pour la décision du prix d'une maison.
Donc on va remplacer les na par 'Other', les int par zéro et les variables de type float par la moyenne de la variable, comme suit :

In [8]:
#Regrouper les colonnes de type object : 
categ_columns = [col for col in df.columns if df[col].dtype == 'O']
In [9]:
#Regrouper les colonnes de type Int64 : 
int_columns = [col for col in df.columns if df[col].dtype == 'int64']
#Enlever saleprice : 
int_columns = int_columns[:-1] 
In [10]:
#Idem pour dtype float :
flt_columns = [col for col in df.columns if df[col].dtype == 'float64']
In [11]:
#On remplace les valeurs na par 0 :
for col in int_columns:
    df[col].fillna(0, inplace = True)
    df_Valid[col].fillna(0, inplace = True)
In [12]:
#Remplacer toutes les valeurs nulles/vides par la valeur 'Other':
for col in categ_columns:
    df[col].fillna('Other', inplace = True)
    df_Valid[col].fillna('Other', inplace = True)
In [13]:
#On remplace les valeurs float par la moyenne de la variable:
for col in flt_columns:
    df[col].fillna(np.mean(df[col]), inplace = True)
    df_Valid[col].fillna(np.mean(df_Valid[col]), inplace = True)
In [14]:
#concat deux variables : 
df_total = pd.concat([df, df_Valid])
In [15]:
#La normalisation des floats : 
for col in flt_columns:
    df[col] = df[col] / np.max(df_total[col])
    df_Valid[col] = df_Valid[col] / np.max(df_total[col])

On plot deux graphes pour vérifier si on a plus de valeurs manquantes.

In [16]:
#Vérification de la suppression, remplacement des valeurs manquantes et aberrantes sur df:
sns.heatmap(df.isnull(), yticklabels = False, cbar= False)
Out[16]:
<matplotlib.axes._subplots.AxesSubplot at 0x1edc272d400>
In [17]:
#Vérification de la suppression, remplacement des valeurs manquantes et aberrantes:
sns.heatmap(df_Valid.isnull(), yticklabels = False, cbar= False)
Out[17]:
<matplotlib.axes._subplots.AxesSubplot at 0x1edc27854a8>

D'après les deux figures, on est assuré qu'on a supprimé toutes les valeurs manquantes. On peut maintenant commencer l'analyse des données comme étant 2ème étape.

2.Analyse du data :

On commence par une visualisation de la variable à prédire en fonction des autres variables :

In [18]:
df['SalePrice'].describe()
Out[18]:
count      1460.000000
mean     180921.195890
std       79442.502883
min       34900.000000
25%      129975.000000
50%      163000.000000
75%      214000.000000
max      755000.000000
Name: SalePrice, dtype: float64

La moyenn des prix des maisons est de l'ordre de 180921 dollar. La majorité des prix sont entre : 129975 et 214000 dollar .

Nous traçons ensuite l'histogramme de distribution de la variable 'SalePrice', et le graphe de la loi normale.

In [19]:
x = pd.Series(df['SalePrice'], name="Sale Price variable")
ax = sns.distplot(x)

Le graphique montre que la distribution de SalePrice s'écarte de la distribution normale, qu'elle a une valeur maximale et qu'elle est biaisée positivement, on traçera l'histograme de log ( 'SalePrice' ). Mais il ne suit pas la ligne diagonale (en-dessous à droite), la ligne diagonale représente la distribution normale dans le graphique de probabilité normale, et une bonne distribution des données doit suivre cette ligne de près

In [20]:
from scipy import stats
import seaborn as sns
sns.set()
plt.figure()
plt.subplot(1, 2, 1)
plt.title("Sale Prices Dist")
sns.distplot(df['SalePrice'], fit=stats.norm)
plt.subplot(1, 2, 2)
stats.probplot(df['SalePrice'], plot=plt)
plt.show()
print("Skewness: %f" % df['SalePrice'].skew())
print("Kurtosis: %f" % df['SalePrice'].kurt())
Skewness: 1.882876
Kurtosis: 6.536282

Afin de résoudre cette problématique, on va tenter la trasformation logarithmique de la variable target :

In [21]:
target = np.log(df['SalePrice'])
sns.set()
plt.figure()
plt.subplot(1, 2, 1)
plt.title("Sale Prices Dist")
sns.distplot(target, fit=stats.norm)
plt.subplot(1, 2, 2)
stats.probplot(target, plot=plt)
plt.show()
print("Skewness: %f" % target.skew())
print("Kurtosis: %f" % target.kurt())
Skewness: 0.121335
Kurtosis: 0.809532

Le graphique ci-dessus, il est évident que la distribution des données suit mieux la ligne diagonale que la précédente, bien qu'il existe des valeurs aberrantes (outliers), il semble donc que la transformation du log est un bon choix pour transformer les données.

On passe maintenat à l'étude de corrélation entre les variables numériques:

In [22]:
# Matrice de corrélation :
corr = df.corr()
f, ax = plt.subplots(figsize=(16, 12))
sns.heatmap(corr, vmax=0.7, square=True)
Out[22]:
<matplotlib.axes._subplots.AxesSubplot at 0x1edc37b6160>

On peut pas déterminer facilement les variables corrélées avec notre variable à prédire, on a besoin de zoomer sur la variable 'SalePrice'.

In [23]:
var_corr = corr['SalePrice'].sort_values(ascending=False)
#on examine la corrélation de la variable 'SalePrice' avec les variables avec une corrélation plus de la valeur absolue de 0.5.
var_corr = var_corr[abs(var_corr) >= 0.5]
var_corr = var_corr[var_corr.index != 'SalePrice']
var_corr
Out[23]:
OverallQual     0.790982
GrLivArea       0.708624
GarageCars      0.640409
GarageArea      0.623431
TotalBsmtSF     0.613581
1stFlrSF        0.605852
FullBath        0.560664
TotRmsAbvGrd    0.533723
YearBuilt       0.522897
YearRemodAdd    0.507101
Name: SalePrice, dtype: float64

On a donc un classement décroissant des variables numériques ayant coef de corrélation plus de 0.5, dont la variable 'OverallQual' est au top de la liste. Mais comment elle est la corrélation entre les deux variables?

In [24]:
#On plot la variable 'SalePrice' en fonction 'OverallQual'
overall_qual = pd.concat([df['SalePrice'], df['OverallQual']], axis=1)
sns.set()
f, ax = plt.subplots(figsize=(8, 6))
fig = sns.boxplot(x='OverallQual', y="SalePrice", data=overall_qual)
fig.axis(ymin=0, ymax=800000)
plt.show()

Le prix de la maison augmente avec la variable catégorielle 'OverallQual' qui Évalue le matériel global et la finition de la maison, où le nombre 10 désigne 'Très excellent' et 1 : 'Very Poor'.
Regardons maintenenant les autres corrélation (des variables résultats de matrice de corrélation) avec 'SalePrice' .

In [25]:
#Corr avec GrLivArea: 
plt.scatter(x=df['GrLivArea'], y=df['SalePrice'])
plt.ylabel('Sale Price')
plt.xlabel('Above grade (ground) living area square feet')
plt.show()

D'après le plot, on dire qu' à première vue, on voit que l’augmentation de la surface habitable correspond à l’augmentation du prix.

In [26]:
#Corr avec GarageArea: 
plt.scatter(x=df['GarageArea'], y=df['SalePrice'])
plt.ylabel('Sale Price')
plt.xlabel('Garage Area')
plt.show()

le plot visualise la superficie du garage. On doit tenir en compte que les garages de superficie zéro c'est les valeurs qu'on remplacer par zéro, ie , une maison sans garage. On constate aussi que l'existence des outliers: des valeur aberrante influencent certains paramètres statistiques, comme la moyenne. Cela peut fausser notre compréhension du jeu de données et nous conduire à émettre des hypothèses erronées sur ce dernier. Pour avoir des modèles de prédiction qui fonctionne mieux on a besoin de supprimer ces outliers.
Vu que la variable nous interesse plus -elle est corrélée avec 'GarageCars' qu'on va garder- on peut ne pas suprimer les outliers.

On trace de nouveau le plot du 'SalePrice' en fonction du 'GarageArea' :

In [27]:
plt.scatter(x=df['GarageArea'], y=df['SalePrice'])
#On force par la suivante xlimite pour avoir les mêmes conditions :
plt.xlim(-200,1600) 
plt.ylabel('Sale Price')
plt.xlabel('Garage Area')
plt.show()

Voici le plot des variables 'intéressantes':

In [28]:
sns.set()
cols = ['SalePrice', 'OverallQual', 'GrLivArea', 'GarageCars', 'GarageArea', 'TotalBsmtSF', '1stFlrSF', 'FullBath', 'TotRmsAbvGrd', 'YearBuilt']
sns.pairplot(df[cols], size=2.5)
plt.show()