Tutoriel python : la distribution des données

Table des matières

Introduction

  1. Visualiser une distribution de données

1.1. Distribution uniforme

1.2. Distribution gaussienne (normale)

1.3. Distribution exponentielle

1.4. Distribution beta

  1. Modéliser une distribution de données

2.1. Importer les données

2.2. Ajuster les paramètres

2.3. Evaluer la modélisation

2.4. La bibliothèque FITTER

  1. Exercices

3.1. Exercice 1

3.2. Exercice 2

  1. Solution des exercices:

4.1. Exercice 1

4.2. Exercice 2

Conclusion 

Introduction

Dans ce Tutoriel, vous apprendrez comment générer la densité de probabilité de plusieurs lois, créer et visualiser des histogrammes et enfin modéliser une distribution de données (Distribution Fitting, en anglais). 

La modélisation d’une distribution de données est le processus utilisé pour sélectionner une loi de probabilité (loi exponentielle, loi beta …) qui correspond le mieux aux données. Ce processus commence par ajuster (estimer) les paramètres d’une ou plusieurs lois de probabilité.  Une fois cette estimation terminée, il faut évaluer les différentes lois ajustées pour déterminer quelle distribution correspond le mieux à vos données. 

Juste une brève note sur les données elles-mêmes.  Les données doivent être générées à partir d'un processus aléatoire.  Si le processus n'est pas aléatoire, l'ajustement de la distribution ne sera pas précis, voire erroné.

Nous pensons que maintenant vous pouvez commencer ce tutoriel ! Allons-y. 

1. Visualiser une distribution de données   

Syntaxe:

import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
from scipy import stats

1.1. Distribution uniforme

L'une des distributions les plus simples et les plus utiles est la distribution uniforme. La fonction de densité (probability density function (pdf) en anglais) de la loi uniforme sur l'intervalle [a , b] est :

Pour visualiser la densité de probabilité de la loi uniforme avec python, vous devez d’abord importer la fonction uniforme (uniform) du module scipy.stats. En utilisant les paramètres loc (facteur de localisation) etscale (facteur d’échelle) de la méthode pdf(), vous obtenez la densité de probabilité uniforme sur l’intervalle [a=loc, b=loc + scale].

Syntaxe :

from scipy.stats import uniform
domain = np.linspace(1,6)
pdf_uniform = uniform.pdf(domain, loc=2, scale=3)

Vous pouvez utiliser plt.plot() pour tracer votre densité de probabilité.

Syntaxe:

plt.plot(domain, pdf_uniform, color='black')
plt.show()

Résultat d’exécution:

Pour générer une distribution de données qui suit une loi uniforme sur l’intervalle [a=loc, b=loc + scale], nous utiliserons la méthode rvs(). Le paramètre size détermine la taille de la distribution générée.

Syntaxe:

data_uniform = uniform.rvs(size=10000, loc=2, scale=3)

Ensuite, vous pouvez enregistrer les données générées dans une dataframe et utiliser la méthode describe de pandas pour afficher un résumé:

Syntaxe:

df=pd.DataFrame(data_uniform, columns=['Données'])
df.describe()

Résultat d’exécution:

Pour tracer l'histogramme de la distribution de données que vous venez de créer, utilisez plt.hist(). Vous pouvez spécifier le nombre d’intervalles dans votre histogramme avec le paramètre bins, spécifier la couleur de l'histogramme avec le paramètre color et spécifier la couleur des bordures avec le paramètre edgecolor. Nous utiliserons aussi l'option density=True pour normaliser les données.

Syntaxe:

plt.figure(figsize = (12,7))
plt.hist(data_uniform, edgecolor='black', bins=30, alpha=.3, density=True, color='red', label='Distribution de données uniforme')
plt.plot(domain, pdf_uniform, color='black', label='Densité de probabilié uniforme')
plt.legend()
plt.show()

Résultat d’exécution:

1.2. Distribution gaussienne (normale)

La fonction de densité centrée (espérance = 0) réduite (variance = 1) de la loi normale est définie pour tout x par :

Pour visualiser la densité de probabilité, importez la fonction normale (norm) du module scipy.stats. En utilisant les paramètres loc (facteur de localisation) et scale (facteur d'échelle) de la méthode pdf(), vous obtenez la densité de probabilité de la loi normale d’espérance = loc et d’écart type = scale (pour la visualiser, utilisez plt.plot()) :

Syntaxe:

from scipy.stats import norm
domain=np.linspace(0,20)
pdf_norm = norm.pdf(domain, loc=10, scale=3)
plt.plot(domain, pdf_norm, color='black')
plt.show()

Résultat d’exécution:

Essayez de modifier le facteur de localisation (loc) et le facteur d’échelle (scale) pour voir leur impact sur la fonction de densité.

Pour générer une distribution de données qui suit une loi normale, utilisez la méthode rvs() de scipy :

Syntaxe:

data_norm = norm.rvs(size=10000, loc=10, scale=3)

Pour tracer l'histogramme de la distribution de données que vous venez de créer, utilisez plt.hist() :

Syntaxe:

plt.figure(figsize=(12,7))
plt.hist(data_norm, edgecolor='black', bins=30, alpha=.3, density=True, color='red', label='Distribution de données uniforme')
plt.plot(domain, pdf_norm, color='black', label='Densité de probabilié uniforme')
plt.legend()
plt.show()

Résultat d’exécution:

1.3. Distribution exponentielle

La fonction de densité normalisée de la loi exponentielle de paramètre ? est définie pour tout x positif par :

Pour visualiser la densité de probabilité, importez la fonction exponentielle (expon) du module scipy.stats. En utilisant les paramètres loc (facteur de localisation) et scale (facteur d’échelle) de la méthode pdf(), vous obtenez la densité de probabilité de la loi exponentielle d’espérance = écart type = 1/? = scale. Pour tracer la densité de probabilité de la loi exponentielle pour différents facteurs de localisation, utilisezplt.plot():

Syntaxe:

from scipy.stats import expon
domain=np.linspace(0,30)
pdf_expon_loc0 = expon.pdf(domain, loc=0, scale=5)
pdf_expon_loc2 = expon.pdf(domain, loc=2, scale=5)
pdf_expon_loc5 = expon.pdf(domain, loc=5, scale=5)
plt.plot(domain, pdf_expon_loc0, color='black', label='loc = 0')
plt.plot(domain, pdf_expon_loc2, color='blue', label='loc = 2')
plt.plot(domain, pdf_expon_loc5, color='red', label='loc = 5')
plt.legend()
plt.show()

Résultat d’exécution:

Pour générer une distribution de données qui suit une loi exponentielle, utilisez la méthode rvs() de scipy :

Syntaxe:

data_expon = expon.rvs(size=10000, loc=0, scale=5)

Pour tracer l'histogramme de la distribution de données que vous venez de créer, utilisez plt.hist() :

Syntaxe:

plt.figure(figsize=(12,7))
plt.hist(data_expon, edgecolor='black', bins=30, alpha=.3, density=True, color='red', label='Distribution de données exponentielle')
plt.plot(domain, pdf_expon_loc0, color='black', label='Densité de probabilié exponentielle')
plt.legend()
plt.xlim(0, 30)
plt.show()

Résultat d’exécution:

1.4. Distribution beta

La fonction de densité de la loi beta de paramètres ? et ? est définie pour tout x entre 0 et 1 par :

Vous l’avez compris, faut commencer par importez la fonction beta (beta) du module scipy.stats. Contrairement aux distributions précédentes, il faut ajouter un autre paramètre à la fonction pdf() de scipy : *arg telle que arg = (?,?) en plus des paramètres loc (facteur de localisation) et scale (facteur d’échelle) pour obtenir la densité de probabilité de la loi beta. Pour tracer la densité de probabilité de la loi beta pour différents paramètres (?,?), utilisez plt.plot():

Syntaxe:

from scipy.stats import beta
domain=np.linspace(0,1)
arg1=(1,1)
pdf_beta1 = beta.pdf(domain, *arg1, loc=0, scale=1)
arg2=(2,4)
pdf_beta2 = beta.pdf(domain, *arg2, loc=0, scale=1)
arg3=(4,2)
pdf_beta3 = beta.pdf(domain, *arg3, loc=0, scale=1)
plt.plot(domain, pdf_beta1, color='black', label='a=1, b=1')
plt.plot(domain, pdf_beta2, color='red', label='a=2, b=4')
plt.plot(domain, pdf_beta3, color='blue', label='a=4, b=2')
plt.legend()
plt.show()

Résultat d’exécution:

Remarquez que pour ? = 1 et ? = 1, la loi beta est tout simplement la loi uniforme continue.

Pour générer une distribution de données qui suit une loi beta, utilisez la méthode rvs() de scipy :

Syntaxe:

data_beta = beta.rvs(size=10000, *arg2, loc=0, scale=1)

Pour tracer l'histogramme de la distribution de données que vous venez de créer, utilisez plt.hist() :

Syntaxe:

plt.figure(figsize=(12,7))
plt.hist(data_beta, edgecolor='black', bins=30, alpha=.3, density=True, color='red',label='Distribution de données beta')
plt.plot(domain, pdf_beta2, color='black', label='Densité de probabilié beta')
plt.legend()
plt.show()

Résultat d’exécution:

2. Modéliser une distribution de données 

La modélisation de la distribution de données consiste à bien choisir une distribution (loi de probabilité) qui convient bien aux données. Dans l'exemple ci-dessus, vous serez amené à ajuster les différents paramètres (trouver les paramètres optimaux) de chaque distribution afin qu’elles reflètent le mieux vos données, pour ensuite sélectionner la meilleure loi de probabilité.

2.1. Importer les données

Il faut commencer à importer des tables de données dont nous ne connaissons pas la distribution (données mesurées aléatoirement). Dans ce tutoriel, nous utiliserons la bibliothèque pydataset. Installez-la avec la commande suivante :

Syntaxe:

!pip install pydataset 

Importez le module data qui contient plusieurs tables de données.

Syntaxe:

from pydataset import data
data().head()

Résultat d’exécution:

Pour afficher la liste des tables de données existantes dans le module data, utilisez la commande suivante:

Syntaxe:

data()['dataset_id'][:15].tolist()

Résultat d’exécution:

Dans ce tutoriel, nous utiliserons la table de données nommée movies. Créez la data frame correspondante et affichez les premières lignes :

Syntaxe:

df_movies = data('movies')
df_movies.head()

Résultat d’exécution:

Dans la table de données movies, nous utiliserons la colonne rating comme la distribution de données à modéliser. Affichez un résumé de cette distribution de données :

Syntaxe:

df.movies['rating'].describe()

Résultat d’exécution:

Comme dans la première partie de ce tutoriel, visualisez l'histogramme de la distribution de données :

Syntaxe:

plt.hist(df_movies['rating'], edgecolor='black', bins=30 , alpha=.3, density=False, color='red')
plt.show()

Résultat d’exécution:

C’est cette distribution de données que vous allez essayer de modéliser. D’après le premier regarde, cette distribution a la forme d’une distribution beta voire même une distribution normale.

2.2. Ajuster les paramètres

Plusieurs distributions sont généralement testées par rapport aux données afin de déterminer laquelle correspond le mieux. Dans ce tutoriel, nous utiliserons que la loi normale et beta vu précédemment pour modéliser la distribution de données précédente. Pour ajuster les paramètres de chaque loi afin qu’elles reflètent le mieux vos données, il suffit de spécifier la loi que l’on souhaite tester, et d’utiliser la méthode fit()de Scipy pour récupérer les paramètres optimaux :

Syntaxe:

dist_names = ['norm', 'beta']
param = []
for distribution in dist_names:
dist = getattr(stats, distribution)
parameters = dist.fit(df_movies['rating'])
param.append(parameters)
print('paramètres de la loi normale:')
print('arg = ', param[0][:-2])
print('loc = ', param[0][-2])
print('scale =', param[0][-1])
print('\nparamètres de la loi beta:')
print('arg = ', param[1][:-2])
print('loc = ', param[1][-2])
print('scale =', param[1][-1])

Résultat d’exécution:

Remarquez que la loi normale n’a pas de paramètres (arg est vide), contrairement à la loi beta qui a deux paramètres (?, ?) (voir la première section).

Ensuite, créez la densité de probabilité de chaque loi en utilisant les paramètres précédents :

Syntaxe:

pdf_list = []
domain = np.linspace( df_movies['rating'].min(), df_movies['rating'].max() )
for i, distribution in enumerate(dist_names):
arg = param[i][:-2]
loc = param[i][-2]
scale = param[i][-1]
dist = getattr(stats , distribution)
pdf = dist.pdf(domain, *arg, loc=loc, scale=scale)
pdf_list.append(pdf)

Visualisez l'histogramme de la distribution de données superposé avec les deux fonctions de densité déjà crées :

Syntaxe:

plt.plot(domain, pdf_list[0], color='black', label='loi normal')
plt.plot(domain, pdf_list[1], color='blue', label='loi beta')
plt.hist(df_movies['rating'] ,edgecolor='black', bins=30 , alpha=.3, density=True, color='red')
plt.legend()
plt.show()

Résultat d’exécution:

Remarquez que la loi beta modélise la distribution de données mieux que la loi normale.

2.3. Evaluer la modélisation

Vous ne pouvez pas vous contenter d'examiner la forme de la distribution et de supposer qu'elle loi correspond bien à vos données.

Comment déterminer la meilleure distribution ?  Dans ce tutoriel, nous utiliserons deux méthodes :

- Le test de Kolmogorov-Smirnov : Ce test est implémenté dans scipy (stats.kstest). La variable sur laquelle nous nous baserons pour déterminer s'il s'agit d'une bonne modélisation ou non est la valeur p (p_value) renvoyée par ce test. Je vous suggère de lire plus sur le test de Kolmogorov-Smirnov et ses limites. En résumé, une p_value faible indique une mauvaise modélisation.

- La somme de résidus au carré (sum of squared errors, en anglais).

Une fois que nous aurons terminé ce processus pour toutes nos distributions définies, nous choisirons celle qui convient le mieux.

Syntaxe:

dist_names = ['beta','norm']
sum_square_error = []
p_value=[]
for distribution in dist_names:
y, x= np.histogram(df_movies['rating'], bins=100, density=True)
x = (x + np.roll(x, -1))[:-1] / 2.0
######## méthode fit
dist = getattr(stats, distribution)
parameters = dist.fit(df_movies['rating'])
######## paramètres
loc = parameters[-2]
scale = parameters[-1]
arg = parameters[:-2]
######## Sum square error
pdf = dist.pdf(x, *arg, loc=loc, scale=scale)
sse = np.sum( (y - pdf)**2 )
sum_square_error.append(sse)
######## p_value
p=stats.kstest(df_movies['rating'], distribution, parameters)[1]
p_value.append(p)
results = pd.DataFrame()
results['Distribution'] = dist_names
results['Résidus au carré'] = sum_square_error
results['p_value'] = p_value
results.sort_values(['Résidus au carré'], inplace=True, ascending=True)
###### rapport
print ('Classement des distributions:')
results

Résultat d’exécution:

2.4. La bibliothèque FITTER

La bibliothèque fitter fournit des méthodes simples permettant d'identifier la distribution qui modélise le mieux une distribution de données. Il utilise 80 distributions de scipy et vous permet de tracer les résultats pour vérifier la distribution la plus probable et les meilleurs paramètres.

Installez la bibliothèque :

Syntaxe:

!pip install fitter

Importez le module Fitter et précisez en paramètres les distributions que vous souhaitez tester :

Syntaxe:

from fitter import Fitter
f = Fitter(df_movies['rating'], distributions = ('beta', 'norm') )
f.fit()
f.summary()

Résultat d’exécution:

Si vous nous précisez pas les distributions que vous souhaiter tester, en sortie vous aurez les 5 meilleures lois qui modélisent le mieux les données parmi les 80 distributions de scipy (à utiliser avec précaution):

Syntaxe:

from fitter import Fitter
f = Fitter(df_movies['rating'])
f.fit()
f.summary()

Résultat d’exécution:

3. Exercices

3.1. Exercice 1 

La loi de puissance 

Question 1: Visualiser la fonction de densité de la loi de puissance avec python.

Question 2: Créer une distribution de données qui suit la loi de puissance et visualiser son histogramme.

Vous pouvez obtenir de l’aide avec la commande :

help( stats.powerlaw )

3.2. Exercice 2 

On va utiliser la table de données movies.

Question 1: Visualiser l’histogramme de la colonne year.

Question 2: Ajuster les paramètres de la distribution suivante: Loi de puissance, pour modéliser la distribution de données précédente.

Question 3: Visualiser la modélisation.

4. Solution des exercices:

4.1. Exercice 1

Question 1:

Syntaxe :

from scipy.stats import powerlaw
domain=np.linspace(0,1)
arg1 = (1,)
pdf_powerlaw1 = powerlaw.pdf(domain, *arg1, loc=0, scale=1)
arg2 = (5,)
pdf_powerlaw2 = powerlaw.pdf(domain, *arg2, loc=0, scale=1)
arg3 = (10,)
pdf_powerlaw3 = powerlaw.pdf(domain, *arg3, loc=0, scale=1)
plt.plot(domain, pdf_powerlaw1, color='black', label = 'a=1')
plt.plot(domain, pdf_powerlaw2, color='red', label = 'a=5')
plt.plot(domain, pdf_powerlaw3, color='blue', label = 'a=10')
plt.legend()
plt.show()

Résultat d’exécution:

Question 2:

Syntaxe :

data_powerlaw = powerlaw.rvs(size=10000, *arg3, loc=0, scale=1)
plt.figure(figsize=(12,7))
plt.hist(data_powerlaw, edgecolor='black', bins=30, alpha=.3, density=True, color='red',label='Distribution de données loi de puissance')
plt.plot(domain, pdf_powerlaw3, color='black', label='Densité de probabilié loi de puissance')
plt.legend()
plt.show()

Résultat d’exécution:

4.2. Exercice 2

Solution :

Question 1 :

Syntaxe :

df_movies = data('movies')
plt.hist(df_movies['year'],edgecolor='black', bins=30 , alpha=.3, density=False, color='red')
plt.show()

Résultat d’exécution:

Question 2 :

Syntaxe :

from scipy.stats import powerlaw
param = powerlaw.fit(df_movies['year'])
print('paramètres de la loi de puissance:')
print('arg = ', param[:-2])
print('loc = ', param[-2])
print('scale =', param[-1])

Résultat d’exécution:

Question 3 :

Syntaxe :

domain=np.linspace( df_movies['year'].min(), df_movies['year'].max() )
arg = param[:-2]
loc = param[-2]
scale = param[-1]
pdf = powerlaw.pdf(domain, *arg, loc=loc, scale=scale)
plt.plot(domain, pdf, color='blue', label='loi de puissance')
plt.hist(df_movies['year'] ,edgecolor='black', bins=30 , alpha=.3, density=True, color='red')
plt.legend()
plt.show()

Résultat d’exécution:

Conclusion

Nous somme arrivé à la fin de ce tutoriel. J’espère que vous êtes capable maintenant de visualiser les distributions de données et les modéliser en utilisant les différentes lois de probabilité fournis par scipy.

Merci d’avoir lu et bon courage pour la suite.

Article publié le 10 Novembre 2020par Sami Nadif