Statistiques : les bibliothèques $\mathtt{NumPy}$ et $\mathtt{Pandas}$ ¶
Retour au tutoriel général
- Si l'on travaille avec une liste :
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.
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.
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.
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.
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
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 :
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...).
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
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.
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()
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
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 :
titanic["Age"]
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.
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.
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 :
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).
x=titanic["Age"].to_numpy()
type(x)
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}$.
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
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.
# 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.
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}$
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}$.
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.
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}$.
groupement_par_genre.mean().axes
[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
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
titanic.plot(x="data1", y=["data2", "data3"])
# 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
# 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()
# 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()
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).
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()
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}$:
titanic_group.plot.bar(y=["Survived","Fare"], subplots=True, layout=(2,1))
plt.show()
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}$.
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()
- 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