Statistiques : les bibliothèques $\mathtt{NumPy}$ et $\mathtt{Pandas}$ ¶

Retour au tutoriel général

La bibliothèque $\mathtt{Numpy}$ possède un certain nombre de fonctions utiles pour calculer des statistiques basiques.¶

Le descriptif de la bibliothèque $\mathtt{NumPy}$ est détaillé dans le paragraphe accessible ici.

  • Si l'on travaille avec une liste :
In [1]:
import numpy as np
x = [0,1,3,4,1]

print(np.min(x))
print(np.max(x))

print("Le nombre d\'occurrences de 1 est", x.count(1))

print("Moyenne : ",np.mean(x)) 
print("Ecart-type : ",np.std(x))

print("Médiane : ", np.median(x))
print("Quantile 0.25 : ", np.quantile(x,0.25))
0
4
Le nombre d'occurrences de 1 est 2
Moyenne :  1.8
Ecart-type :  1.469693845669907
Médiane :  1.0
Quantile 0.25 :  1.0

Si l'on travaille avec un $\mathtt{np.array}$, le fonctionnement est identique à part le calcul des effectifs.

In [2]:
x = np.array([0,1,3,4,1])

print(np.count_nonzero(x == 1))
2

La fonction $\mathtt{unique}$ avec l'option $\mathtt{return}\_\mathtt{counts}$ permet de calculer les modalités et les effectifs.

In [3]:
x = np.array([1, 0, 1, 2, 0, 0])
modalites, effectifs = np.unique(x, return_counts=True)
print("Modalités :", modalites)
print("Effectifs :", effectifs)
Modalités : [0 1 2]
Effectifs : [3 2 1]

La fonction $\mathtt{cumsum}$ (pour "cumulative sum") permet alors d'obtenir les effectifs cumulés.

In [4]:
print("Effectifs cumulés :", np.cumsum(effectifs))
Effectifs cumulés : [3 5 6]

Si l'on veut calculer le mode d'une série statistique on peut utiliser la fonction $\mathtt{where}$. Celle-ci renvoie la liste des indices vérifiant la condition donnée en argument.

In [5]:
x = np.array([1,0,2,1,2,2,0])

print(np.where(x==1))
(array([0, 3]),)
  • Covariance, corrélation et régression linéaire
In [6]:
import numpy as np
x = [1, 2, 3, 4, 5, 6, 7, 8, 9]
y = [9, 8, 7, 6, 5, 4, 3, 2, 1]

print("Matrice de covariance : ")
print(np.cov(x,y,bias=True))
print("Matrice de corrélation : ")
print(np.corrcoef(x,y))
Matrice de covariance : 
[[ 6.66666667 -6.66666667]
 [-6.66666667  6.66666667]]
Matrice de corrélation : 
[[ 1. -1.]
 [-1.  1.]]

L'option $\mathtt{bias=True}$ permet d'avoir la valeur calculée de la covariance. Si on l'oublie c'est une estimation qui est légèrement différente de la valeur calculée...

Remarquez que le résultat de $\mathtt{np.cov(x,y)}$ (c'est le même principe pour la corrélation) est une matrice définie par $$ \begin{pmatrix} \operatorname{Cov}(X,X) & \operatorname{Cov}(X,Y) \\ \operatorname{Cov}(Y,X) & \operatorname{Cov}(Y,Y) \end{pmatrix}. $$

La covariance $\operatorname{Cov}(X,Y)$ s'obtient donc ainsi :

In [7]:
x = [1, 2, 3, 4, 5, 6, 7, 8, 9]
y = [9, 8, 7, 6, 5, 4, 3, 2, 1]

print("Covariance de X et Y = ", np.cov(x,y,bias=True)[0][1])
Covariance de X et Y =  -6.666666666666666

Les coefficients de la droite de régression linéaire peuvent être obtenus avec la fonction $\mathtt{polyfit(x,y,1)}$. L'argument $1$ précise que l'on cherche un polynôme de degré $1$ (donc une droite...).

In [8]:
import numpy as np
import matplotlib.pyplot as plt

# Création des données
x = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9])
y = np.array([9, 8, 7, 6, 5, 4, 3, 2, 1]) + np.array([2*np.random.rand() for i in range(9)])

# Tracé du nuage de points du nuage de points
plt.scatter(x,y)

# Calcul de corrélation
print("Corrélation entre X et Y = ", np.corrcoef(x,y)[0][1])

# Calcul des coefficients de la droite de régression linéaire
a, b = np.polyfit(x,y,1)
print("La droite de régression linéaire a pour équation y=",round(a,3),"x+",round(b,3))

# Tracé de la droite de régression linéaire
x_trace = np.linspace(1,9,100)
plt.plot(x_trace, a*x_trace+b , 'red')
plt.show()
Corrélation entre X et Y =  -0.9801817110052893
La droite de régression linéaire a pour équation y= -1.059 x+ 11.527
No description has been provided for this image

Pour information, la bibliothèque $\mathtt{statistics}$ permet de réaliser les mêmes opérations. La syntaxe est décrite à l'adresse https://docs.python.org/3/library/statistics.html#module-statistics

Visualisation des données¶

Un certain nombre de tracés utiles à la visualisation des données est présenté dans la section dédiée à Matplotlib notamment les fonctions

  • $\mathtt{bar}$ pour le tracé de diagrammes en bandes
  • $\mathtt{pie}$ pour le tracé de diagrammes en secteurs
  • $\mathtt{hist}$ pour le tracé d'histogrammes
  • et $\mathtt{scatter}$ pour le tracé de nuages de points.

Il existe aussi la fonction $\mathtt{boxplot}$ pour le tracé des diagrammes en boite.

In [9]:
import matplotlib.pyplot as plt
import numpy as np

plt.close()
x= [np.random.randint(10, 16) for i in range(1000)]
plt.boxplot(x, whis=[0,100], vert=False)
plt.show()
No description has been provided for this image

La bibliothèque $\mathtt{Pandas}$ ¶

La bibliothèque $\mathtt{Pandas}$ permet de traiter des fichiers de données de différents types, de faire des statistiques sur ces données et de les visualiser.

Dans ce tutoriel nous allons travailler avec le fichier suivant (issu de la documentation de $\mathtt{Pandas}$) au format .csv http://mmorancey.perso.math.cnrs.fr/titanic.csv

Ce paragraphe du tutoriel est très fortement inspiré de la documentation de $\mathtt{Pandas}$ disponible à l'adresse https://pandas.pydata.org/docs/getting_started/index.html#intro-to-pandas

  • Lecture du fichier csv
In [10]:
import pandas

titanic = pandas.read_csv("./titanic.csv")

# Affichage de la table
print("Affichage de la table")
print(titanic)

print("Affichage des cinq premiers éléments")
print(titanic.head(5))

print("Affichage des trois derniers éléments")
print(titanic.tail(3))
Affichage de la table
     PassengerId  Survived  Pclass     Sex   Age     Fare
0              1         0       3    male  22.0   7.2500
1              2         1       1  female  38.0  71.2833
2              3         1       3  female  26.0   7.9250
3              4         1       1  female  35.0  53.1000
4              5         0       3    male  35.0   8.0500
..           ...       ...     ...     ...   ...      ...
886          887         0       2    male  27.0  13.0000
887          888         1       1  female  19.0  30.0000
888          889         0       3  female   NaN  23.4500
889          890         1       1    male  26.0  30.0000
890          891         0       3    male  32.0   7.7500

[891 rows x 6 columns]
Affichage des cinq premiers éléments
   PassengerId  Survived  Pclass     Sex   Age     Fare
0            1         0       3    male  22.0   7.2500
1            2         1       1  female  38.0  71.2833
2            3         1       3  female  26.0   7.9250
3            4         1       1  female  35.0  53.1000
4            5         0       3    male  35.0   8.0500
Affichage des trois derniers éléments
     PassengerId  Survived  Pclass     Sex   Age   Fare
888          889         0       3  female   NaN  23.45
889          890         1       1    male  26.0  30.00
890          891         0       3    male  32.0   7.75

L'utilisation de la table est proche de celle d'un dictionnaire. Par exemple, pour récupérer la colonne des ages des passagers :

In [11]:
titanic["Age"]
Out[11]:
0      22.0
1      38.0
2      26.0
3      35.0
4      35.0
       ... 
886    27.0
887    19.0
888     NaN
889    26.0
890    32.0
Name: Age, Length: 891, dtype: float64

On peut alors n'extraire que certaines données de la table à l'aide de la méthode $\mathtt{loc}$ : par exemple seulement les passagers mineurs ou même seulement les passagers mineurs de 3ème classe.

In [12]:
Jeunes_passagers = titanic.loc[titanic["Age"]<18]
print("Premiers éléments de la table des passagers mineurs :")
print(Jeunes_passagers.head(3))
print("")
Jeunes_passagers_3eme_classe = titanic.loc[(titanic["Age"]<18) & (titanic["Pclass"]==3)]
print("Table des passagers mineurs de 3ème classe :")
print(Jeunes_passagers_3eme_classe)
Premiers éléments de la table des passagers mineurs :
    PassengerId  Survived  Pclass     Sex   Age     Fare
7             8         0       3    male   2.0  21.0750
9            10         1       2  female  14.0  30.0708
10           11         1       3  female   4.0  16.7000

Table des passagers mineurs de 3ème classe :
     PassengerId  Survived  Pclass     Sex   Age     Fare
7              8         0       3    male   2.0  21.0750
10            11         1       3  female   4.0  16.7000
14            15         0       3  female  14.0   7.8542
16            17         0       3    male   2.0  29.1250
22            23         1       3  female  15.0   8.0292
..           ...       ...     ...     ...   ...      ...
844          845         0       3    male  17.0   8.6625
850          851         0       3    male   4.0  31.2750
852          853         0       3  female   9.0  15.2458
869          870         1       3    male   4.0  11.1333
875          876         1       3  female  15.0   7.2250

[78 rows x 6 columns]

La méthode $\mathtt{iloc}$ permet d'accéder aux éléments de la table à partir des numéros de ligne et de colonne.

In [13]:
print("Le premier passager de la liste :")
print(titanic.iloc[0,:])

print("Les 3 premières colonnes des 10 premiers passagers :")
titanic.iloc[0:10,0:3]
Le premier passager de la liste :
PassengerId       1
Survived          0
Pclass            3
Sex            male
Age            22.0
Fare           7.25
Name: 0, dtype: object
Les 3 premières colonnes des 10 premiers passagers :
Out[13]:
PassengerId Survived Pclass
0 1 0 3
1 2 1 1
2 3 1 3
3 4 1 1
4 5 0 3
5 6 0 3
6 7 0 1
7 8 0 3
8 9 1 3
9 10 1 2
  • Utilisation de $\mathtt{Numpy}$.

Une première possibilité pour traiter les données numériques est de les convertir au format $\mathtt{Numpy}$ et d'utiliser l'arsenal à notre disposition (aussi bien pour le calcul des paramètres de position et de dispersion que pour la visualisation).

In [14]:
x=titanic["Age"].to_numpy()
type(x)
Out[14]:
numpy.ndarray

Attention, lorsque l'on travaille avec des données réelles, il est possible qu'il y ait des données manquantes (valeur $\mathtt{NULL}$ en SQL par exemple). En $\mathtt{Python}$ ces valeurs sont représentées par $\mathtt{nan}$ (qui signifie 'not a number'). L'ensemble des fonctions précédentes doit alors être remplacé par $\mathtt{nanmean}$, $\mathtt{nanmedian}$ etc... pour ne pas prendre en compte ces $\mathtt{nan}$.

In [15]:
x = np.array([0,1,3,np.nan,4,1])

print("Moyenne : ",np.mean(x)) 
print("Moyenne sans le nan : ", np.nanmean(x))
Moyenne :  nan
Moyenne sans le nan :  1.8
In [16]:
x = x[np.logical_not(np.isnan(x))]
print(x)
[0. 1. 3. 4. 1.]
  • La bibliothèque $\mathtt{Pandas}$ propose cependant ses propres fonctions pour calculer les divers indicateurs. Cela évite d'avoir à gérer les données manquantes manuellement.
In [17]:
# Moyenne de la colonne Age
print("Age moyen")
print(titanic["Age"].mean())
print("")

# Médiane de certaines colonnes
print("Mediane de certaines donnees")
print(titanic[["Age", "Fare"]].median())
print("")

print("Nombre de passagers dont l'âge est connu")
print(titanic["Age"].count())
Age moyen
29.69911764705882

Mediane de certaines donnees
Age     28.0000
Fare    14.4542
dtype: float64

Nombre de passagers dont l'âge est connu
714

Il est même possible d'afficher tous les indicateurs statistiques avec la méthode $\mathtt{describe}$ : effectif, moyenne, écart-type, minimum, maximum et quartiles.

In [18]:
print(titanic.describe())
       PassengerId    Survived      Pclass         Age        Fare
count   891.000000  891.000000  891.000000  714.000000  891.000000
mean    446.000000    0.383838    2.308642   29.699118   32.204208
std     257.353842    0.486592    0.836071   14.526497   49.693429
min       1.000000    0.000000    1.000000    0.420000    0.000000
25%     223.500000    0.000000    2.000000   20.125000    7.910400
50%     446.000000    0.000000    3.000000   28.000000   14.454200
75%     668.500000    1.000000    3.000000   38.000000   31.000000
max     891.000000    1.000000    3.000000   80.000000  512.329200

Les modalités et effectifs s'obtiennent avec la méthode $\mathtt{value}\_\mathtt{counts}$

In [19]:
print(titanic["Age"].value_counts())
24.00    30
22.00    27
18.00    26
28.00    25
19.00    25
         ..
55.50     1
74.00     1
0.92      1
70.50     1
12.00     1
Name: Age, Length: 88, dtype: int64

Pour calculer la corrélation, il faut d'abord spécifier les indicateurs concernés (sous la forme d'une liste d'où le double $\mathtt{[}$ dans $\mathtt{titanic[["Survived","Pclass"]]}$ dans l'exemple ci-dessous) puis utiliser la méthode $\mathtt{corr}$.

In [20]:
print("Matrice de corrélation :" ,titanic[["Survived","Pclass"]].corr())

print("\n Coefficient de corrélation :" ,titanic[["Survived","Pclass"]].corr().iloc[0][1])
Matrice de corrélation :           Survived    Pclass
Survived  1.000000 -0.338481
Pclass   -0.338481  1.000000

 Coefficient de corrélation : -0.33848103596101514

Si besoin, on peut grouper les informations selon les variables qualitatives. Ici on accède à l'âge moyen, le pourcentage de survivants et le prix moyen du ticket selon le genre des passagers.

In [21]:
groupement_par_genre = titanic.groupby("Sex")[["Age","Survived","Fare"]]
print(groupement_par_genre.mean())
              Age  Survived       Fare
Sex                                   
female  27.915709  0.742038  44.479818
male    30.726645  0.188908  25.523893

L'accès aux noms des colonnes se fait par la méthode $\mathtt{axes}$.

In [22]:
groupement_par_genre.mean().axes
Out[22]:
[Index(['female', 'male'], dtype='object', name='Sex'),
 Index(['Age', 'Survived', 'Fare'], dtype='object')]
  • De même que pour les indicateurs statistiques, $\mathtt{Pandas}$ propose ses fonctions de visualisation (basées sur celles de $\mathtt{Matplotlib}$ donc acceptant les mêmes paramètres). Quelques exemples sont proposés ci-dessous.

Pour tracer la courbe de la donnée $\mathtt{data2}$ en fonction de la donnée $\mathtt{data1}$ on utilise la syntaxe

In [ ]:
titanic.plot(x="data1", y="data2")

Pour tracer sur un même graphique les courbes des données $\mathtt{data2}$ et $\mathtt{data3}$ en fonction de la donnée $\mathtt{data1}$ on utilise la syntaxe

In [ ]:
titanic.plot(x="data1", y=["data2", "data3"])
In [24]:
# Diagramme en secteurs

import matplotlib.pyplot as plt

donnees = titanic.groupby("Sex")["Sex"].count()
print(donnees)

donnees.plot.pie(autopct = lambda z: str(round(z, 2)) + '%', pctdistance = 0.6)
plt.show()
Sex
female    314
male      577
Name: Sex, dtype: int64
No description has been provided for this image
In [25]:
# Diagramme en boite
import matplotlib.pyplot as plt

titanic["Age"].plot.box(whis=[0,100],vert=False)
plt.title("Diagramme en boite de l'age des passagers")
plt.show()
No description has been provided for this image
In [26]:
# Diagramme en bandes
import matplotlib.pyplot as plt

donnees = titanic.groupby("Pclass")["Survived"].mean()
donnees.plot.bar(width=0.5,edgecolor='black')
plt.title("Pourcentage de survivants par classe de passagers")
plt.show()
No description has been provided for this image

Les fonctions préimplémentées de visualisation de $\mathtt{Pandas}$ permettent de facilement visualiser plusieurs données ensemble (la syntaxe est ici détaillée sur les diagrammes en bandes mais est valable pour tous les tracés).

In [27]:
titanic_group = titanic.groupby("Pclass").mean()   # on groupe les passagers par classe et on calcule la moyenne 
                                                   # de chaque colonne
titanic_group.plot.bar(y=["Survived","Fare"], secondary_y="Fare")  # on affiche le diagramme du nombre de survivants
                                                                   # et celui du prix du ticket
plt.show()
No description has been provided for this image

Lorsque les variables affichées ont des valeurs très différentes il faut considérer plusieurs échelles. Dans l'exemple précédent l'option $\mathtt{secondary}\_\mathtt{y}$ permet d'afficher les prix avec l'échelle de droite (ce qui est indiqué en légende) alors que le taux de survivant est indiqué dans l'échelle de gauche.

On peut aussi aisément afficher plusieurs graphiques sans avoir à configurer le $\mathtt{subplot}$:

In [28]:
titanic_group.plot.bar(y=["Survived","Fare"], subplots=True, layout=(2,1))
plt.show()
No description has been provided for this image

Pour des affichages plus complexes, il est nécessaire de recourir à matplotlib. Ci-dessous, on affiche deux figures contenant chacune deux diagrammes. On peut spécifier où l'on souhaite tracer la figure avec le paramètre $\mathtt{ax}$.

In [29]:
import matplotlib.pyplot as plt
fig, (ax1,ax2) = plt.subplots(1,2)
titanic_group.plot.bar(y=["Survived","Fare"], secondary_y="Fare", ax=ax1)
titanic_group.plot.bar(y=["Survived","Age"], secondary_y="Age", ax=ax2)
fig.tight_layout()   # pour écarter les deux figures
plt.show()
No description has been provided for this image
  • La bibliothèque $\mathtt{Pandas}$ peut gérer les dates dans un format particulier. La méthode $\mathtt{.to\_datetime}$ permet de transformer une colonne (ou de créer une nouvelle colonne) de dates au format $\mathtt{str}$ en format $\mathtt{datetime}$. On peut alors, par exemple, accéder à l'année, au mois ou au jours en utilisant les méthodes $\mathtt{dt.year}$, $\mathtt{dt.month}$ ou $\mathtt{dt.weekday}$. Pour plus d'informations voir https://pandas.pydata.org/docs/user_guide/timeseries.html
In [ ]: