Introduction à Python
Charles Martin
Octobre 2022
Mise en place
Python est un language de programmation général. Contrairement à R ou à MATLAB, il n'a pas été conçu spécifiquement pour l'analyse et la visualisation de données. C'est pourquoi la plupart du code que nous utiliserons aujourd'hui provient de librairies de codes ayant été créées pour ces usages spécifiques.
Bien que beaucoup de systèmes d'exploitation sont livrés avec une version de Python pré-installée (entre autres Ubuntu, MacOS, etc.), sa configuration, l'installation de libraries, etc. peut être relativement périlleux pour un ou une débutante.
C'est pourquoi pour cet atelier, nous travaillerons plutôt avec Python sur Google Colab (https://colab.research.google.com/). Colab est un service offert par Google, où on peut se créer un cahier de notes (Jupyter Notebook) dans lequel on peut mélanger du code (entre autres en Python) et du texte (sous format Markdown). Comme tout les logiciels nécessaires sont déjà pré-installés, nous économiserons BEAUCOUP de temps de configuration.
On peut d'ailleurs, immédiatement, vérifier que notre cahier de notes fonctionne bien en lançant une première commande de test
print("Hello, World!")
Hello, World!
Cela dit, si jamais vous envie de travailler directement sur vos ordinateurs, je vous conseille d'installer Python à travers un gestionnaire de librairies (par exemple Anaconda). Cette façon de faire vous permettra, entre autres, d'éviter les conflits de versions entre vos différents projets.
Les bases de Python
Python peut s'utiliser comme une calculatrice
1+1
2
3*5
15
Les exposants sont différents de ceux que l'on voit souvent (i.e. 2^5)
2**8
256
On peut garder nos résultats dans un objet
= 3+2 mon_resultat
*6 mon_resultat
30
Les listes
Nous n'aurons ici (évidemment!) pas le temps de tout explorer les structures de données et fonctions possibles de Python.
Nous prendrons tout de même le temps d'en apprivoiser une, qui devrait être la plus utile, soit les listes
= ['bouleau','érable','chêne'] especes
On peut accéder aux divers éléments d'une liste à partir de leur index, qui commence à 0 (plutôt qu'à 1, c'est une vieille guerre de programmeurs)
print(especes[0])
bouleau
On peut aussi modifier les éléments d'une liste
2] = 'sapin'
especes[print(especes)
['bouleau', 'érable', 'sapin']
En ajouter, etc.
'épinette')
especes.append(print(especes)
['bouleau', 'érable', 'sapin', 'épinette']
Remarquez dans l'exemple précédent l'utilisation de la syntaxe object.fonction.
Nous n'irons pas trop creux dans ces détails aujourd'hui, mais puisque Python est un language orienté-objet, chacun des objets possède une série d'actions (des fonctions) qu'ils peuvent accomplir et de données associées. Pour accédér à ces derniers, on utilise la notation objet.méthode ou objet.donnée.
On peut aussi supprimer des items, soit par position, ou par leur valeur directement
del especes[1]
'bouleau')
especes.remove(print(especes)
['sapin', 'épinette']
Remarquez que si vous utilisez la méthode par valeur, seule la première valeur sera supprimée si vous travaillez de cette façon.
Les boucles et les fonctions
Pour automatiser les choses en Python, on peut entre autres, utiliser des fonctions et des boucles
On peut par exemple imprimer le nom de chacune des espèces comme ceci
for espece in especes :
print(espece)
sapin
épinette
Remarquez que, dans Python, les espaces devant le code sont conventionnés et importants.
Tout le texte qui est en retrait fait partie de la boucle. Pas besoin d'accolades, de parenthèses, etc. C'est très élégant!
On peut aussi se créer une fonction qui, par exemple, vérifie si notre espèce est une épinette
def cest_une_epinette(x) :
if x == 'épinette' :
return "oui"
else :
return "non"
for espece in especes :
print(espece)
print(cest_une_epinette(espece))
sapin
non
épinette
oui
Les dictionnaires de données
Une autre structure de données importante de Python se nomme les dictionnaires de données. Alors que les listes ne contiennent que des séries de valeurs, les dictionnaires contiennent des paires d'associations clé-valeur.
Ils sont définis en utilisant les accolades plutôt que les parenthèses carrées.
= {'nom' : 'charles', 'age' : 42, 'ville': 'Trois-Rivières'}
infos infos
{'nom': 'charles', 'age': 42, 'ville': 'Trois-Rivières'}
On accède tout de même aux éléments d'un dictionnaire à l'aide des parenthèses carrées
'nom'] infos[
{"type":"string"}
On peut obtenir l'ensemble des clés ou des valeurs comme ceci :
print(infos.keys())
print(infos.values())
dict_keys(['nom', 'age', 'ville'])
dict_values(['charles', 42, 'Trois-Rivières'])
Il est possible de combiner différentes structures de données pour former des objets complexes, comme par exemple une liste de dictionnaires :
= [
repondants 'nom' : 'Charles', 'language' : 'R'},
{'nom' : 'Alex', 'language' : 'Python'}
{
]
for repondant in repondants :
print(repondant['nom']+' préfère ' + repondant['language'])
Charles préfère R
Alex préfère Python
Vectorisation des opérations
Contrairement à plusieurs languages créés expressément pour l'analyse de données, Python n'est pas un language naturellement vectorisé.
Si on se prépare une liste et que l'on veut multiplier tous ses items par 2, on ne peut PAS faire ceci :
= [1,2,3,4] liste
*2 liste
[1, 2, 3, 4, 1, 2, 3, 4]
On pourrait évidemment contourner le problème avec des boucles
= []
nouvelle_liste
for chiffre in liste :
*2)
nouvelle_liste.append(chiffre
nouvelle_liste
[2, 4, 6, 8]
Python possède une notation plus compacte pour ce genre de problèmes, que l'on pourrait traduire par les listes en compréhension (List Comprehension)
* 2 for x in liste] [x
[2, 4, 6, 8]
Il s'agit d'une structure très compacte, permettant de créer une liste à partir d'une autre liste.
Enfin, si vous avez beaucoup d'algèbre vectoriel ou matriciel à faire, il sera probablement plus simple d'utiliser la librairie prévue à cet effet, qui se nomme NumPy.
NumPy (et toutes les autres librairies nécessaires à l'atelier) sont déjà installées sur Colab.
Sur vos ordinateurs personnels, on installe NumPy par la ligne de commande (terminal), par exemple comme ceci :
pip install numpy
Dans Python, lorsque l'on active une librarie, tout le code chargé est associé à un préfixe, que l'on peut modifier au moment de l'activation
import numpy as np
= np.array([1,2,3,4])
tableau print(tableau)
print(tableau*2)
[1 2 3 4]
[2 4 6 8]
= np.array([[1,2,3,4],[5,6,7,8]])
matrice print(matrice)
[[1 2 3 4]
[5 6 7 8]]
print(matrice.dot(tableau))
[30 70]
Les tableaux de données pandas
Il existe une librairie gérant les tableaux de données de façon beaucoup plus appropriée que les listes ou les dictionnaires lorsqu'il s'agit de l'analyse statistiques de données. Cette librairie se nomme pandas.
Elle tient son nom d'une structure de données commune en économie, les PANel DAta.
import pandas as pd
Charger et vérifier les données
La fonction de pandas pour charger des données se nomme read_csv.
Pour se simplifier la vie, nous allons charger des données directement disponibles sur le web
= pd.read_csv('https://raw.githubusercontent.com/mwaskom/seaborn-data/master/iris.csv')
iris iris
sepal_length | sepal_width | petal_length | petal_width | species | |
---|---|---|---|---|---|
0 | 5.1 | 3.5 | 1.4 | 0.2 | setosa |
1 | 4.9 | 3.0 | 1.4 | 0.2 | setosa |
2 | 4.7 | 3.2 | 1.3 | 0.2 | setosa |
3 | 4.6 | 3.1 | 1.5 | 0.2 | setosa |
4 | 5.0 | 3.6 | 1.4 | 0.2 | setosa |
... | ... | ... | ... | ... | ... |
145 | 6.7 | 3.0 | 5.2 | 2.3 | virginica |
146 | 6.3 | 2.5 | 5.0 | 1.9 | virginica |
147 | 6.5 | 3.0 | 5.2 | 2.0 | virginica |
148 | 6.2 | 3.4 | 5.4 | 2.3 | virginica |
149 | 5.9 | 3.0 | 5.1 | 1.8 | virginica |
150 rows × 5 columns
Si jamais vos données sont en format Excel, il existe aussi une fonction read_excel permettant de les lire directement, sans passer par le format CSV.
Une fois les données chargées, il est important de vérifier le contenu de notre tableau de données, par exemple avec la méthode info :
iris.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 150 entries, 0 to 149
Data columns (total 5 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 sepal_length 150 non-null float64
1 sepal_width 150 non-null float64
2 petal_length 150 non-null float64
3 petal_width 150 non-null float64
4 species 150 non-null object
dtypes: float64(4), object(1)
memory usage: 6.0+ KB
Trier les observations
En ordre croissant
'sepal_length') iris.sort_values(
sepal_length | sepal_width | petal_length | petal_width | species | |
---|---|---|---|---|---|
13 | 4.3 | 3.0 | 1.1 | 0.1 | setosa |
42 | 4.4 | 3.2 | 1.3 | 0.2 | setosa |
38 | 4.4 | 3.0 | 1.3 | 0.2 | setosa |
8 | 4.4 | 2.9 | 1.4 | 0.2 | setosa |
41 | 4.5 | 2.3 | 1.3 | 0.3 | setosa |
... | ... | ... | ... | ... | ... |
122 | 7.7 | 2.8 | 6.7 | 2.0 | virginica |
118 | 7.7 | 2.6 | 6.9 | 2.3 | virginica |
117 | 7.7 | 3.8 | 6.7 | 2.2 | virginica |
135 | 7.7 | 3.0 | 6.1 | 2.3 | virginica |
131 | 7.9 | 3.8 | 6.4 | 2.0 | virginica |
150 rows × 5 columns
Ou en ordre décroissant
'sepal_length', ascending = False) iris.sort_values(
sepal_length | sepal_width | petal_length | petal_width | species | |
---|---|---|---|---|---|
131 | 7.9 | 3.8 | 6.4 | 2.0 | virginica |
135 | 7.7 | 3.0 | 6.1 | 2.3 | virginica |
122 | 7.7 | 2.8 | 6.7 | 2.0 | virginica |
117 | 7.7 | 3.8 | 6.7 | 2.2 | virginica |
118 | 7.7 | 2.6 | 6.9 | 2.3 | virginica |
... | ... | ... | ... | ... | ... |
41 | 4.5 | 2.3 | 1.3 | 0.3 | setosa |
42 | 4.4 | 3.2 | 1.3 | 0.2 | setosa |
38 | 4.4 | 3.0 | 1.3 | 0.2 | setosa |
8 | 4.4 | 2.9 | 1.4 | 0.2 | setosa |
13 | 4.3 | 3.0 | 1.1 | 0.1 | setosa |
150 rows × 5 columns
##Sélectionner des lignes
Il existe plusieurs façon de sélectionner des lignes ou des colonnes avec pandas, mais la façon la plus générale est d'utiliser l'opérateur loc.
Ce dernier peut accepter soit un liste de valeurs booléennes, soit des étiquettes ou une séquence entre deux étiquettes.
Cet opérateur vous permet aussi de sélectionner simultanément une liste de colonnes ET de lignes dans la même opération.
== "virginica"] iris.loc[iris.species
sepal_length | sepal_width | petal_length | petal_width | species | |
---|---|---|---|---|---|
100 | 6.3 | 3.3 | 6.0 | 2.5 | virginica |
101 | 5.8 | 2.7 | 5.1 | 1.9 | virginica |
102 | 7.1 | 3.0 | 5.9 | 2.1 | virginica |
103 | 6.3 | 2.9 | 5.6 | 1.8 | virginica |
104 | 6.5 | 3.0 | 5.8 | 2.2 | virginica |
105 | 7.6 | 3.0 | 6.6 | 2.1 | virginica |
106 | 4.9 | 2.5 | 4.5 | 1.7 | virginica |
107 | 7.3 | 2.9 | 6.3 | 1.8 | virginica |
108 | 6.7 | 2.5 | 5.8 | 1.8 | virginica |
109 | 7.2 | 3.6 | 6.1 | 2.5 | virginica |
110 | 6.5 | 3.2 | 5.1 | 2.0 | virginica |
111 | 6.4 | 2.7 | 5.3 | 1.9 | virginica |
112 | 6.8 | 3.0 | 5.5 | 2.1 | virginica |
113 | 5.7 | 2.5 | 5.0 | 2.0 | virginica |
114 | 5.8 | 2.8 | 5.1 | 2.4 | virginica |
115 | 6.4 | 3.2 | 5.3 | 2.3 | virginica |
116 | 6.5 | 3.0 | 5.5 | 1.8 | virginica |
117 | 7.7 | 3.8 | 6.7 | 2.2 | virginica |
118 | 7.7 | 2.6 | 6.9 | 2.3 | virginica |
119 | 6.0 | 2.2 | 5.0 | 1.5 | virginica |
120 | 6.9 | 3.2 | 5.7 | 2.3 | virginica |
121 | 5.6 | 2.8 | 4.9 | 2.0 | virginica |
122 | 7.7 | 2.8 | 6.7 | 2.0 | virginica |
123 | 6.3 | 2.7 | 4.9 | 1.8 | virginica |
124 | 6.7 | 3.3 | 5.7 | 2.1 | virginica |
125 | 7.2 | 3.2 | 6.0 | 1.8 | virginica |
126 | 6.2 | 2.8 | 4.8 | 1.8 | virginica |
127 | 6.1 | 3.0 | 4.9 | 1.8 | virginica |
128 | 6.4 | 2.8 | 5.6 | 2.1 | virginica |
129 | 7.2 | 3.0 | 5.8 | 1.6 | virginica |
130 | 7.4 | 2.8 | 6.1 | 1.9 | virginica |
131 | 7.9 | 3.8 | 6.4 | 2.0 | virginica |
132 | 6.4 | 2.8 | 5.6 | 2.2 | virginica |
133 | 6.3 | 2.8 | 5.1 | 1.5 | virginica |
134 | 6.1 | 2.6 | 5.6 | 1.4 | virginica |
135 | 7.7 | 3.0 | 6.1 | 2.3 | virginica |
136 | 6.3 | 3.4 | 5.6 | 2.4 | virginica |
137 | 6.4 | 3.1 | 5.5 | 1.8 | virginica |
138 | 6.0 | 3.0 | 4.8 | 1.8 | virginica |
139 | 6.9 | 3.1 | 5.4 | 2.1 | virginica |
140 | 6.7 | 3.1 | 5.6 | 2.4 | virginica |
141 | 6.9 | 3.1 | 5.1 | 2.3 | virginica |
142 | 5.8 | 2.7 | 5.1 | 1.9 | virginica |
143 | 6.8 | 3.2 | 5.9 | 2.3 | virginica |
144 | 6.7 | 3.3 | 5.7 | 2.5 | virginica |
145 | 6.7 | 3.0 | 5.2 | 2.3 | virginica |
146 | 6.3 | 2.5 | 5.0 | 1.9 | virginica |
147 | 6.5 | 3.0 | 5.2 | 2.0 | virginica |
148 | 6.2 | 3.4 | 5.4 | 2.3 | virginica |
149 | 5.9 | 3.0 | 5.1 | 1.8 | virginica |
Remarquez que, si on accède à une seule colonne à la fois et que le nom de la colonne est un identifiant valide de Python (pas d'espace, pas d'accents, etc.), on peut l'accéder directement avec un .variable plutôt que ['variable']
Sélectionner des colonnes
Le principe est le même pour sélectionner des colonnes. On doit par contre à ce moment spécifier quelles lignes on veut obtenir (ou spécifier toutes les lignes, comme ceci)
"sepal_width", "species"]] iris.loc[:,[
sepal_width | species | |
---|---|---|
0 | 3.5 | setosa |
1 | 3.0 | setosa |
2 | 3.2 | setosa |
3 | 3.1 | setosa |
4 | 3.6 | setosa |
... | ... | ... |
145 | 3.0 | virginica |
146 | 2.5 | virginica |
147 | 3.0 | virginica |
148 | 3.4 | virginica |
149 | 3.0 | virginica |
150 rows × 2 columns
Et comme discuté, on peut combiner les deux opérations dans une même commande :
== "virginica",["sepal_width", "species"]] iris.loc[iris.species
sepal_width | species | |
---|---|---|
100 | 3.3 | virginica |
101 | 2.7 | virginica |
102 | 3.0 | virginica |
103 | 2.9 | virginica |
104 | 3.0 | virginica |
105 | 3.0 | virginica |
106 | 2.5 | virginica |
107 | 2.9 | virginica |
108 | 2.5 | virginica |
109 | 3.6 | virginica |
110 | 3.2 | virginica |
111 | 2.7 | virginica |
112 | 3.0 | virginica |
113 | 2.5 | virginica |
114 | 2.8 | virginica |
115 | 3.2 | virginica |
116 | 3.0 | virginica |
117 | 3.8 | virginica |
118 | 2.6 | virginica |
119 | 2.2 | virginica |
120 | 3.2 | virginica |
121 | 2.8 | virginica |
122 | 2.8 | virginica |
123 | 2.7 | virginica |
124 | 3.3 | virginica |
125 | 3.2 | virginica |
126 | 2.8 | virginica |
127 | 3.0 | virginica |
128 | 2.8 | virginica |
129 | 3.0 | virginica |
130 | 2.8 | virginica |
131 | 3.8 | virginica |
132 | 2.8 | virginica |
133 | 2.8 | virginica |
134 | 2.6 | virginica |
135 | 3.0 | virginica |
136 | 3.4 | virginica |
137 | 3.1 | virginica |
138 | 3.0 | virginica |
139 | 3.1 | virginica |
140 | 3.1 | virginica |
141 | 3.1 | virginica |
142 | 2.7 | virginica |
143 | 3.2 | virginica |
144 | 3.3 | virginica |
145 | 3.0 | virginica |
146 | 2.5 | virginica |
147 | 3.0 | virginica |
148 | 3.4 | virginica |
149 | 3.0 | virginica |
Remarquez que le tableau original n'est pas affecté par ces opérations. Si on veut conserver le résultat, on doit le garder dans un objet
iris.shape
(150, 5)
= iris.loc[iris.species == "virginica",["sepal_width", "species"]] iris_modifie
iris.shape
(150, 5)
iris_modifie.shape
(50, 2)
##Ajouter des colonnes
= iris.sepal_length / iris.petal_length) iris.assign(ratio
sepal_length | sepal_width | petal_length | petal_width | species | ratio | |
---|---|---|---|---|---|---|
0 | 5.1 | 3.5 | 1.4 | 0.2 | setosa | 3.642857 |
1 | 4.9 | 3.0 | 1.4 | 0.2 | setosa | 3.500000 |
2 | 4.7 | 3.2 | 1.3 | 0.2 | setosa | 3.615385 |
3 | 4.6 | 3.1 | 1.5 | 0.2 | setosa | 3.066667 |
4 | 5.0 | 3.6 | 1.4 | 0.2 | setosa | 3.571429 |
... | ... | ... | ... | ... | ... | ... |
145 | 6.7 | 3.0 | 5.2 | 2.3 | virginica | 1.288462 |
146 | 6.3 | 2.5 | 5.0 | 1.9 | virginica | 1.260000 |
147 | 6.5 | 3.0 | 5.2 | 2.0 | virginica | 1.250000 |
148 | 6.2 | 3.4 | 5.4 | 2.3 | virginica | 1.148148 |
149 | 5.9 | 3.0 | 5.1 | 1.8 | virginica | 1.156863 |
150 rows × 6 columns
Résumer les données
Pour avoir un aperçu de l'ensemble des statistiques descriptives de notre tableau de données, on peut utiliser la fonction describe
iris.describe()
sepal_length | sepal_width | petal_length | petal_width | |
---|---|---|---|---|
count | 150.000000 | 150.000000 | 150.000000 | 150.000000 |
mean | 5.843333 | 3.057333 | 3.758000 | 1.199333 |
std | 0.828066 | 0.435866 | 1.765298 | 0.762238 |
min | 4.300000 | 2.000000 | 1.000000 | 0.100000 |
25% | 5.100000 | 2.800000 | 1.600000 | 0.300000 |
50% | 5.800000 | 3.000000 | 4.350000 | 1.300000 |
75% | 6.400000 | 3.300000 | 5.100000 | 1.800000 |
max | 7.900000 | 4.400000 | 6.900000 | 2.500000 |
Si on a besoin de résumer nos données de façon plus fine, on peut spécifier les fonctions et les colonnes manuellement
'sepal_length', 'petal_length']].agg(['mean','min','max','count']) iris.loc[:,[
sepal_length | petal_length | |
---|---|---|
mean | 5.843333 | 3.758 |
min | 4.300000 | 1.000 |
max | 7.900000 | 6.900 |
count | 150.000000 | 150.000 |
On peut aussi appliquer nos résumés sur des groupes en particulier
'species')[['sepal_length', 'petal_length']].mean() iris.groupby(
sepal_length | petal_length | |
---|---|---|
species | ||
setosa | 5.006 | 1.462 |
versicolor | 5.936 | 4.260 |
virginica | 6.588 | 5.552 |
Visualisation avec matplotlib
Le module classique pour la visualisation de données avec Python se nomme matplotlib. En général, les gens utilisent en particulier la collection de fonctions nommée pyplot, qui vise à reproduire l'interface graphique de MATLAB dans Python
import matplotlib.pyplot as plt
Explorer chaque variable individuellement
Pour créer un histogramme de fréquences, la fonction se nomme hist.
'sepal_length', data = iris) plt.hist(
(array([ 9., 23., 14., 27., 16., 26., 18., 6., 5., 6.]),
array([4.3 , 4.66, 5.02, 5.38, 5.74, 6.1 , 6.46, 6.82, 7.18, 7.54, 7.9 ]),
<a list of 10 Patch objects>)
Comme matplotlib et pandas sont extrêmement bien intégrés, il existe, pour la plupart des visualisations, une façon de les appeller directement à partir du tableau de données
iris.sepal_length.plot.hist()
<matplotlib.axes._subplots.AxesSubplot at 0x7f17e8c77a50>
On peut ensuite apporter des modifications à ce graphique (ou au précédent), puis demander à le réafficher
iris.sepal_length.plot.hist()"Fréquence")
plt.ylabel("Longueur des sépales") plt.xlabel(
Text(0.5, 0, 'Longueur des sépales')
Si jamais vous travaillez avec matplotlib dans un script plutôt que sur Jupyter, vous devrez appeller plt.show() pour afficher votre graphique. Ici, Jupyter le fait pour vous.
Si nos données sont qualitatives, on emploie plutôt un diagramme à bandes.
Il faut par contre calculer d'abord nous même les dénombremenets de chacune des classes
iris.species.value_counts().plot.bar()
<matplotlib.axes._subplots.AxesSubplot at 0x7f17e8b20150>
Explorer les relations entre deux variables
Pour regarder la relation entre deux variables quantiatives, on a bien sûr accès au classique nuage de points
'petal_length', 'petal_width') iris.plot.scatter(
<matplotlib.axes._subplots.AxesSubplot at 0x7f17e8af49d0>
Et je vous montre rapidement comment changer la couleur des points parce que j'ai eu un peu de difficulté à trouver comment pour une variable qualitative.
La clé est de d'abord se créer un dictionnaire associant chacune des espèces à une couleur.
Puis au moment de créer le graphique, d'associer chaque valeur d'espèce à une valeur de couleur avec la méthode map.
= {'setosa':'red', 'virginica':'green', 'versicolor':'blue'}
couleurs 'petal_length','petal_width',c=iris.species.map(couleurs)) iris.plot.scatter(
<matplotlib.axes._subplots.AxesSubplot at 0x7f17e8a8be90>
Si on veut explorer la relation entre une variable qualitative et une quantitative, il y a évidemment le boxplot
='sepal_length',by='species', grid = False) iris.boxplot(column
<matplotlib.axes._subplots.AxesSubplot at 0x7f17e89f8150>
Un petit clin d'oeil à R
Si jamais vous vous ennuyez de ggplot2, l'ensemble de la librairie a été ré-implémentée en Python dans la librairie plotnine.
Remarquez qu'il existe tout de même certaines petites nuances vs. le code R. Vous ne pourrez pas copier-coller directement votre code.
from plotnine import ggplot, aes,geom_point
+ aes(x = "sepal_length", y = "sepal_width") + geom_point() ggplot(iris)
<ggplot: (8733791616949)>
Tests statistiques avec scipy
Les tests statistiques classiques dans Python sont fournis par la collection de fonctions stats dans le module scipy
from scipy import stats
Si vous voulez par exemple appliquer un test de T pour variance inégales
stats.ttest_ind(== "virginica", 'petal_length'],
iris.loc[iris.species == "setosa", 'petal_length'],
iris.loc[iris.species = False
equal_var )
Ttest_indResult(statistic=49.98618625709594, pvalue=9.26962758534569e-50)
Si vous voulez mesurer une corrélationn de Pearson (et obtenir la valeur de p correspondante)
stats.pearsonr(
iris.petal_length,
iris.sepal_length )
(0.8717537758865831, 1.0386674194498099e-47)
L'apprentissage automatique (Machine Learning) avec scikit-learn
La référence en matière d'aprentissage automatique (Machine Learning) est sans aucun doute le module Python nommé scikit-learn
Exemple avec un Random Forest
Voici comment on pourrait par exemple appliquer un modèle de classification Random Forest à nos données.
Remarquez qu'il faut d'abord encoder notre variable qualitative en numérique pour que le modèle la comprenne...
from sklearn.preprocessing import LabelEncoder
= LabelEncoder()
le = le.fit_transform(iris.species)
Y
= iris.loc[:,['sepal_length','sepal_width']] X
On peut ensuite lancer le modèle et voir à quel point cela fonctionne bien!
from sklearn.ensemble import RandomForestClassifier
= RandomForestClassifier()
rf
rf.fit(X,Y)
rf.score(X,Y)
0.9266666666666666
Exemple avec une ACP
La librairie sklearn contient une fonction pour calculer une analyse en composantes principales nommé PCA dans le module decomposition. L'ACP se trouve à cet endroit, puisqu'il s'agit, dans le language de la science des données, d'une technique d'apprentissage non-supervisée.
Remarquez que la fonction applique toujours son calcul à la matrice de variance/covariance. Vous devrez vous-même centrer-réduire vos données pour utiliser la matrice de corrélation.
Une fonction pour effectuer cette opération (StandardScaler) se trouve dans le module preprocessing de sklearn.
from sklearn.decomposition import PCA
= iris.drop(columns='species')
donnees_pour_acp
= PCA()
acp = acp.fit_transform(donnees_pour_acp) coordonnees_acp
Voici comment récupérer les eigenvectors
acp.components_
array([[ 0.36138659, -0.08452251, 0.85667061, 0.3582892 ],
[ 0.65658877, 0.73016143, -0.17337266, -0.07548102],
[-0.58202985, 0.59791083, 0.07623608, 0.54583143],
[-0.31548719, 0.3197231 , 0.47983899, -0.75365743]])
Les eigenvalues
acp.explained_variance_
array([4.22824171, 0.24267075, 0.0782095 , 0.02383509])
Et la fraction de la variance expliquée par chacun des axes
acp.explained_variance_ratio_
array([0.92461872, 0.05306648, 0.01710261, 0.00521218])
Enfin, on peut aussi utiliser matplotlib pour visualiser les deux premiers axes de notre ACP comme ceci :
0], coordonnees_acp[:,1]) plt.scatter(coordonnees_acp[:,
<matplotlib.collections.PathCollection at 0x7f17d0756750>
On peut aussi tracer les variables dans le nouveau système d'axes. Par contre, il faut utiliser une boucle pour y arriver, parce que la fonction plt.arrow ne trace qu'une flèche à la fois
= acp.components_[0]
PC1 = acp.components_[1]
PC2
for i in range(len(PC1)):
0, 0, PC1[i], PC2[i], head_width = 0.05)
plt.arrow(list(donnees_pour_acp)[i])
plt.text(PC1[i], PC2[i],0, linestyle = "--")
plt.axvline(0, linestyle = "--")
plt.axhline(-1.5,1.5)
plt.xlim(-1,1) plt.ylim(
(-1.0, 1.0)
Comme ceci n'est pas un atelier de statistiques, je vous laisse le plaisir de mettre à l'échelle les deux données (eigenvectors et points) dans un même graphique avec le scaling de votre choix ;-)
Ressources
Voici en terminant deux ressources qui m'ont été utiles pour construire cet atelier :
Si vous voulez vraiment apprendre Python, le livre le plus recommandé à l'heure actuelle est Python Crash Course, 2nd edition, par Eric Matthes. Au delà des 200 premières pages vous enseignant les bases de Python, les 300 autres sont consacrées à 3 projets vous montrant les différentes facettes du language : un jeu comprenant une interface visuelle, un projet d'analyse de données et une application Web.
Si jamais vous voulez appliquer ce que vous avez vu dans vos cours de statistiques avec Python (et pour chaque bout de code voir l'équivalent en R), je vous conseille Practical Statistics for Data Scientists, Second Edition, par Bruce, Bruce et Gedeck. Il s'agit à la fois d'un des rares livres présentant ses exemples en deux languages et il offre, à mon avis, juste le bon niveau de détail pour quelqu'un qui veut appliquer correctement les bonnes techniques statistiques, sans avoir l'ambition de devenir statistien pour autant.