Python
¶Dans ce TP, nous allons utiliser les packages bokeh
et seaborn
. Comme d'habitude, il faut tout d'abord installer les modules via un terminale de commande. Le module pydataset
contient,lui, plusieurs jeux de données que nous allons utiliser.
{bash}
pip3 install bokeh
pip3 install seaborn
pip3 install pydataset
Si vous rencontrez des erreurs pour l'installation d'un module, vous pouvez l'installer localement avec la commande suivante
{bash}
pip3 install --user package_name
Dans la suite, nous allons utiliser le jeu de données tips
, initialement présent dans le package reshape2
de R
. Pour le récupérer, on importe la fonction data()
du module pydataset
, et on l'obtient avec data("tips")
. Pour avoir la liste des données présentes dans pydataset
, vous pouvez taper la commande data()
(ou aller voir ici).
from pydataset import data
tips = data('tips')
tips.head()
Dans la suite, nous allons utiliser les modules numpy
et pandas
pour réaliser quelques manipulations.
import numpy
import pandas
bokeh
¶Nous devons importer les modules dans le notebook. Voici tout d'abord les instructions pour bokeh
. Pour ce module, ici, nous importons chaque fonction séparemment. Voici à quoi elles servent globalement :
output_notebook()
: initialise le notebook pour la visualisation des graphiques produitsshow()
: montre le graphiquecolor()
: permet de spécifier la palette ou les couleursbins()
: découpe une variable quantitative en différents intervalleslayouts()
: permet de mettre plusieurs graphiques sur la même figureIl existe en plus des fonctions permettant de réaliser un graphique à la main, en accédant à des primitives de dessins, laissant libre cours à votre imagination en terme de Dataviz.
from bokeh.plotting import output_notebook, show
from bokeh.charts import color, Histogram, BoxPlot, Bar, Donut, Scatter, HeatMap, bins
from bokeh import layouts
output_notebook()
Dans aucun de ces deux modules, le QQ plot n'est implémenté directement, il faudra utiliser scipy
pour le faire (non présenté ici).
C'est la fonction Histogram()
qui nous permet de réaliser un histogramme donc, en effectif par défaut.
h = Histogram(tips.total_bill)
show(h)
Il est possible de spécifier le nombre d'intervalles, avec le paramètre bins
.
h = Histogram(tips.total_bill, bins = 10)
show(h)
On peut aussi spécifier les limites des intervalles avec bins
.
p = Histogram(tips.total_bill, bins = [5,10,20,30,60])
show(p)
Mais dans ce cas, le graphique est erroné. Il faut représenter la densité, ce qu'on obtient avec le paramètre density
.
h = Histogram(tips.total_bill, density = True)
show(h)
Pour la boîte à moustaches, la fonction BoxPlot()
est initialement prévu pour le croisement entre une variable qualitative (en $x$) et une variable quantitative (en $y$). Pour l'avoir en univarié, il nous faut donc créer une variable constante (nommée const
ici, égale à 1
).
tips = tips.assign(const = 1)
p = BoxPlot(tips, values = "total_bill", label = "const")
show(p)
Le diagramme en barres est réalisé avec la fonction Bar()
. Il est possible de déterminer une couleur en fonction du sexe avec le paramètre color
.
p = Bar(tips, label = "sex", color = "sex")
show(p)
Il est possible d'avoir le diagramme en barres empilées en représentant une constante en $x$, et en indiquant que l'empilage se fait sur la variable sex
(avec le paramètre stack
).
p = Bar(tips, "const", stack = "sex")
show(p)
Pour avoir ce diagramme sommé à 100, il est nécessaire de calculer tout d'abord les fréquences de chaque modalité dans un tableau. Puis de réprésenter ce tableau, en indiquant que les valeurs sont les pourcentages (via le paramètre values
).
t = pandas.crosstab(tips.sex, "freq", normalize = True)
t = t.assign(sex = t.index, const = 1, percent = 100 * t.freq)
t
p = Bar(t, label = "const", values = "percent", stack = "sex")
show(p)
Enfin, le diagramme circulaire est fait via la fonction Donut()
.
p = Donut(tips, "sex")
show(p)
Le nuage de points e fait via la fonction Scatter()
, en indiquant la variable en $x$ puis la variable en $y$.
p = Scatter(tips, "total_bill", "tip")
show(p)
Un autre graphique intéressant dans ce cas est une heatmap, qui est un histogramme en 2d. Pour cela, la fonction HeatMap
a besoin d'avoir des variables découpées via la fonction bins()
.
p = HeatMap(tips, bins("total_bill"), bins("tip"))
show(p)
Dans cette fonction bins()
, comme pour un histogramme, il est possible de choisir son découpage avec le paramètre bins
(soit via le nombre de bins, soit en donnant les limites des intervalles).
p = HeatMap(tips, bins("total_bill", bins = 5), bins("tip", bins = 7))
show(p)
La fonction Bar()
permet de réaliser le diagramme en barres séparées, en effectifs.
p = Bar(tips, "sex", group = "smoker")
show(p)
Pour avoir ce diagramme en pourcentages (ou proportions), il faut tout d'abord calculer les profils sur la variable sex
.
t = pandas.crosstab(tips.sex, tips.smoker, normalize = "index")
t = t.assign(sex = t.index)
t
Ensuite, nous utilisons la fonction melt()
de pandas
permettant de modifier la structure d'un tableau.
tm = pandas.melt(t, id_vars=["sex"])
tm.value = 100 * tm.value
tm
Enfin, à partir de cette table, il est facile de réaliser le diagramme en barres en pourcentages.
p = Bar(tm, label = "sex", values = "value", group = "smoker")
show(p)
Pour avoir la version empilée, en effectifs, on utilise le code suivant.
p = Bar(tips, "sex", stack = "smoker")
show(p)
En reprenant le tableau tm
créé précédemment, il est possible maintenant d'avoir le diagramme en barres empilées, sommées à 100%.
p = Bar(tm, label = "sex", values = "value", stack = "smoker")
show(p)
Pour avoir un diagramme circulaire d'une variable par modalité d'une autre variable, il est nécessaire de créer plusieurs graphiques et de les mettre ensemble, avec la fonction layouts.row()
(en lignes - et .column()
en colonnes).
pSmokerYes = Donut(tips.query('smoker == "Yes"'), "sex", title = "Yes")
pSmokerNo = Donut(tips.query('smoker == "No"'), "sex", title = "No")
p = layouts.row(pSmokerYes, pSmokerNo)
show(p)
Avec une list comprehension et l'utilisation de liste de paramètre (avec *
), il est possible de réaliser cela en une seule étape.
p = layouts.row(*[Donut(tips.query('smoker == "' + m + '"'), "sex", title = 'smoker: ' + m)
for m in tips.smoker.unique()])
show(p)
La représentation la plus simple à obtenir est les boîtes à moustaches pour chaque modalité, grâce à la fonction BoxPlot()
.
p = BoxPlot(tips, values = "total_bill", label = "sex", color = "sex")
show(p)
Ensuite, nous pouvons créer les histogrammes de total_bill
pour chaque modalité de sex
, avec un layouts
en colonnes (column()
).
p = layouts.column(*[Histogram(tips.query('sex == "' + m + '"'),
"total_bill",
density = True,
title = 'sex: ' + m,
plot_height = 200,
)
for m in tips.sex.unique()])
show(p)
Dans ce cas, il est possible de réaliser une heatmap, dans laquelle chaque rectangle croisement de deux intervalles pour deux variables (ici total_bill
et size
) est coloré en fonction de la valeur moyenne d'une troisième variable (ici tip
).
p = HeatMap(tips, x = bins("total_bill", bins = 5), y = "size", values = "tip",
stat = "mean")
show(p)
Ici, le plus simple est de réaliser un nuage de points, en colorant les points en fonction de la variable qualitative.
p = Scatter(tips, "total_bill", "tip", color = "sex")
show(p)
En reprenant la fonction BoxPlot()
, il est possible de créer un découpage sur plusieurs variables qualitatives en donnant une liste au paramètre label
.
p = BoxPlot(tips, values = "total_bill", label = ["sex", "smoker"], color = ["sex", "smoker"])
show(p)
Pour ce cas, on peut réaliser le diagramme en barres empilées (ou séparées) entre deux variables, pour chaque modalité d'une troisième variable.
p = layouts.column(*[Bar(tips.query('time == "' + m + '"'), "sex",
stack = "smoker", title = 'time: ' + m,
plot_height = 200)
for m in tips.time.unique()])
show(p)
Pour avoir la version sommée à 100%, il faut manipuler en deux étapes :
smoker
sur sex
, pour chaque modalité de time
tm = [pandas.melt(pandas.crosstab(t.sex, t.smoker, normalize = "index")
.assign(sex = t.sex.unique()), id_vars = "sex")
for t in [tips.query("time == '" + m + "'") for m in tips.time.unique()]]
p = layouts.column(*[Bar(tm[i], label = "sex", values = "value",
stack = "smoker", title = "time: " + tips.time.unique()[i],
plot_height = 200)
for i in range(len(tm))])
show(p)
Voici quelques paramètres généraux permettant d'améliorer les graphiques :
title
, xlabel
, ylabel
: titre global et titres des axescolor
: définition de couleurs (il existe aussi des palettes)plot_width
et plot_height
: taille des figurestoolbar_location
: position de la barre d'outilsIl en existe d'autres, à vous de les explorer.
p = Scatter(tips, "total_bill", "tip",
title = "Montant et pourboire en fonction du sexe",
xlabel = "Montant total",
ylabel = "Pourboire",
color = color(["sex"], palette = ["blue", "orange"]),
plot_width = 700, plot_height = 300,
toolbar_location = "above")
show(p)
seaborn
¶Ce module, importé ci-dessous, est basé sur matplotlib
. Il faut donc ajouter la ligne %matplotlib inline
dans un notebook, pour pouvoir voir les graphiques.
Ce module contient toutes les fonctions directement, l'importation est donc assez simple.
import seaborn
%matplotlib inline
La fonction distplot()
nous permet de réaliser les graphiques de distribution d'une variable quantitative. Par défaut, elle réaliser un histogramme avec une estimation de la densité.
seaborn.distplot(tips.total_bill)
Pour ne garder que l'histogramme, on indique qu'on ne souhaite pas l'estimation de la densité (paramètre kde
). Ainsi, l'histogramme devient en effectifs.
seaborn.distplot(tips.total_bill, kde = False)
De même, on ne peut vouloir que la densité. Auquel cas, on supprimer l'histogramme avec le paramètre hist
.
seaborn.distplot(tips.total_bill, hist = False)
Il est possible de choisir le nombre de bins, avec le paramètre bins
.
seaborn.distplot(tips.total_bill, bins = 6, kde = False)
Il est aussi possible de choisir les limites des intervalles, avec le même paramètre bins
. Dans ce cas, il faut bien évidemment veiller à faire un histogramme en densité. Si on ne souhaite pas avoir l'estimation de la densité, on peut l'obtenir tout de même avec le paramètre norm_hist
.
seaborn.distplot(tips.total_bill, bins = [0, 10, 25, 60], norm_hist = True, kde = False)
C'est la fonction boxplot()
qui nous permet de réaliser une boîte à moustache (soit verticale en mettant la variable en y
, soit horizontale en la mettant en x
).
seaborn.boxplot(y = "total_bill", data = tips)
seaborn.boxplot(x = "total_bill", data=tips)
Une autre représentation possible est obtenue avec la fonction pointplot()
, qui représente la moyenne et l'écarte-type, avec le choix entre vertical (y
) ou horizontal (x
).
seaborn.pointplot(y = "total_bill", data = tips)
seaborn.pointplot(x = "total_bill", data = tips)
Un autre graphique possible est celui obtenu avec violinplot()
, qui représente la densité d'une variable, toujours avec le choix vertical/horizontale (y
/x
).
seaborn.violinplot(y = "total_bill", data = tips)
seaborn.violinplot(x = "total_bill", data = tips)
Enfin, il est possible de représenter toutes les valeurs sur un pseudo nuage de points. Avec striplot()
dont l'option jitter
a été activée, les points sont aléatoirement répartis sur l'axe des $x$ (si on utilise y
- inversement sinon).
seaborn.stripplot(y = "total_bill", data = tips, jitter = True)
seaborn.stripplot(x = "total_bill", data = tips, jitter = True)
La fonction factorplot()
regroupe l'ensemble des graphiques précédents (sauf l'histogramme) en une seule fonction. On accède aux différentes sous-fonctions en indiquant dans le paramètre kind
:
point
: moyenne +/- écart-typebox
: boîte à moustachesviolin
: denisté (en symétrie)strip
: pseudo nuage de pointsseaborn.factorplot(y = "total_bill", data = tips, kind = "point")
Le diagramme en barres en effectifs est obtenu via la fonction countplot()
. Il est soit horizontal (avec la variable en x
), soit vertical (en y
).
seaborn.countplot(x = "sex", data = tips)
seaborn.countplot(y = "sex", data = tips)
Pour avoir la version en pourcentages (ou en proportions) de ce graphique, nous devons utiliser la fonction barplot()
, sur la table de proportions calculée avant. Cette fonction réalise un calcul (moyenne par défaut) sur une variable (ici freq
) en fonction des modalités d'une autre variable (sex
ici donc).
t = pandas.crosstab(tips.sex, "freq", normalize=True)
t = t.assign(sex = t.index, freq = 100 * t.freq)
seaborn.barplot(x = "sex", y = "freq", data = t)
seaborn.barplot(x = "freq", y = "sex", data = t)
Pour réaliser un diagramme en barres empilées, il faudra le créer soi-même. Nous ne verrons pas ici.
Enfin, comme précédemment, la fonction factorplot()
nous permet d'accéder aux sous-fonctions avec le choix dans kind
.
count
: diagramme en barres (dénombrement)bar
: diagramme en barres avec calculseaborn.factorplot(x = "sex", data = tips, kind = "count")
Pour réaliser le nuage de points, on utilise la fonction jointplot()
. Elle a l'avantage d'ajouter par défaut les histogrammes de chaque variable. Elle réalise par défaut le nuage de points simple (scatter
). Comme pour factorplot()
, on va pouvoir choisir le type de graphique avec le paramètre kind
.
seaborn.jointplot(x = "total_bill", y = "tip", data = tips)
En choississant le type reg
, on obtient en plus l'ajustement linéaire de la variable en y
par celle en x
.
seaborn.jointplot(x = "total_bill", y = "tip", data = tips, kind = "reg")
On peut obtenir une heatmap, non pas avec des rectangles mais un pavage hexagonal, avec kind = "hex"
.
seaborn.jointplot(x = "total_bill", y = "tip", data = tips, kind = "hex")
Enfin, on peut avoir une estimation de la densité en 2d avec le type kde
.
seaborn.jointplot(x = "total_bill", y = "tip", data = tips, kind = "kde")
Si on souhaite ne pas avoir les distributions marginales, la fonction regplot()
nous permet de réaliser le nuage de points avec ou sans ajustement (paramètre fit_reg
). On peut aussi n'afficher que l'ajustement.
seaborn.regplot("total_bill", "tip", data = tips, fit_reg = False)
seaborn.regplot("total_bill", "tip", data = tips)
seaborn.regplot("total_bill", "tip", data = tips, scatter = False)
Il est possible d'obtenir directement tous les nuages de points 2 à 2, avec la fonction pairplot()
. Le paramètre vars
permet de sélectionner certaines variables. Par défaut, la fonction utilise toutes les variables numériques.
seaborn.pairplot(data = tips, vars = ["total_bill", "tip", "size"])
Pour obtenir le diagramme en barres séparées (en effectifs), nous utilisons la fonction factorplot()
avec le paramètre hue
(celui-ci provient de la fonction countplot()
).
seaborn.factorplot(x = "sex", hue = "smoker", data = tips, kind = "count")
Cette fonction factorplot()
permet aussi un découpage en facette avec les paramètres row
et col
. Ici, nous découpons donc le graphique en fonction des modalités de smoker
.
seaborn.factorplot(x = "sex", col = "smoker", data = tips, kind = "count")
Pour avoir la version en pourcentages, il faut faire les calculs avant, modifier la structure du résultat et les afficher ensuite.
t = pandas.crosstab(tips.sex, tips.smoker, normalize = "columns")
t = t.assign(sex = t.index)
tm = pandas.melt(t, id_vars = "sex")
tm = tm.assign(value = 100 * tm.value)
seaborn.factorplot("sex", y = "value", col = "smoker", data = tm, kind = "bar")
Une autre représentation est de visualiser la table de contingence avec une heatmap (la couleur dépendra du nombre d'individus pour chaque couple de modalité).
seaborn.heatmap(pandas.crosstab(tips.sex, tips.smoker))
Pour réaliser les histogrammes de la variable quantitative pour chaque modalité de la variable qualitative, il faut passer par la fonction FacetGrid()
, permettant de faire un découpage en plusieurs lignes (avec row
) et/ou en plusieurs colonnes (avec col
). On applique ensuite la fonction distplot()
avec les paramètres (ici la variable total_bill
).
p = seaborn.FacetGrid(tips, row = "sex")
p.map(seaborn.distplot, "total_bill")
Les boîtes à moustaches sont elles faciles à créer avec factorplot()
(ou boxplot()
directement).
seaborn.factorplot(x = "sex", y = "total_bill", data = tips, kind = "box")
On peut aussi représenter la moyenne et l'écart-type à l'aide du graphique pointplot
.
seaborn.factorplot(x = "sex", y = "total_bill", data = tips, kind = "point", join = False)
Le graphique violinplot
est bien sûr lui aussi applicable dans ce cas.
seaborn.factorplot(x = "sex", y = "total_bill", data = tips, kind = "violin")
On a aussi la possibilité de représenter le pseudo nuage de points, avec stripplot
(avec jitter
à True
.
seaborn.factorplot(x = "sex", y = "total_bill", data = tips, kind = "strip", jitter = True)
Dans ce cas, nous cherchons à faire une heatmap du croisement entre les versions discrétisées en intervalles de deux variables quantitatives, la couleur d'un rectangle dépendant de la moyenne (ici mean
du module numpy
) d'une troisième variable. On créé la table puis l'affiche.
t = pandas.crosstab(pandas.cut(tips.total_bill, bins = 6),
tips["size"],
values = tips.tip, aggfunc = numpy.mean)
seaborn.heatmap(t)
Dans ce cas, il est possible de faire le nuage de points avec la fonction lmplot()
, en utilisant le principe de grille (comme factorplot()
) avec un découpage en colonnes (via col
). On peut aussi améliorer la distinction en ajoutant une couleur différente sur la variable sex
avec le paramètre hue
.
seaborn.lmplot("total_bill", "tip", hue = "sex", col = "sex", data = tips)
Il est possible de créer les histogrammes de la variable quantitative pour chaque couple de modalités sur les deux variables qualitatives avec FacetGrid()
.
p = seaborn.FacetGrid(tips, row = "sex", col = "smoker")
p.map(seaborn.distplot, "total_bill")
Pour les boîtes à moustaches, on utilise la fonction factorplot()
qui permet d'ajouter une couleur en fonction d'une variable qualitative via le paramètre hue
.
seaborn.factorplot(x = "sex", y = "total_bill", hue = "smoker", data = tips, kind = "box")
Cette même fonction factorplot()
permet le découpage en lignes (row
) ou en colonnes (col
), qui nous est utile pour le graphique point
.
seaborn.factorplot(x = "sex", y = "total_bill", hue = "smoker", col = "smoker", data = tips,
kind = "point", join = False)
Le graphique violin
s fait lui très facilement.
seaborn.factorplot(x = "sex", y = "total_bill", hue = "smoker", data = tips, kind = "violin")
Et pour le graphique strip
, on reprend le découpage via col
.
seaborn.factorplot(x = "sex", y = "total_bill", hue = "smoker", col = "smoker", data = tips,
kind = "strip", jitter = True)
seaborn.factorplot(x = "sex", row = "smoker", col = "time", data = tips, kind = "count")
seaborn.factorplot(x = "sex", hue = "smoker", col = "time", data = tips, kind = "count")
Pour avoir la version sommée à 100%, il faut calculer la table en premier, la restructurer et l'afficher.
t = pandas.crosstab([tips.smoker, tips.time], tips.sex, normalize = "index")
t = t.assign(smoker_time = t.index)
tm = pandas.melt(t, id_vars="smoker_time")
tm = tm.assign(value = 100 * tm.value)
seaborn.factorplot(x = "smoker_time", y = "value", hue = "sex", data = tm,
kind = "bar")
Il est bien évidemment possible de personnaliser le graphique de différentes façons, dont certains sont présentées ci-dessous. On accède aux fonctions de personnalisation soit via des paramètres de la fonction, soit via l'objet renvoyé par la fonction utilisée pour créer le graphique, soit via le module directement. Dans ce cas, ce sont des changements qui affecteront aussi les graphiques futurs.
suptitle
dans fig
: titre globalset_axis_labels
: titre des axespalette
: choix d'une palette de couleurs size
et aspect
: hauteur et ratio entre hauteur et largeur, pour chaque facette (une seule ici)seaborn.set_style("white")
p = seaborn.factorplot(x = "size", y = "tip", hue = "sex", data = tips, kind = "box",
palette = "Set2", size = 4, aspect = 2)
p.fig.suptitle("Taille et pourboire en fonction du sexe")
p.set_axis_labels("Nombre de convives", "Pourboire")
A partir du jeu de données Computers
présent dans le module pydataset
, vous devez répondre aux questions suivantes, avec bokeh
et seaborn
. Vous pourrez trouver des informations sur ce jeu de données en exécutant data("Computers", show_doc = True)
dans le notebook.
ordis = data("Computers")
ordis.head()
ordis.to_csv("donnees/Computers.csv")
Vous pouvez télécharger le fichier Computers.csv
, s'il n'est pas présent dans votre installation du module pydataset
. Voici comment le charger dans python
avec la librairie pandas
.
ordis_csv = pandas.read_csv("donnees/Computers.csv")
ordis_csv.head()
price
(histogramme, boîte à moustaches, ...)price
et les variablesspeed
hd
ram
cd
premium
screen
price
l'impact de ces couples de variablesspeed
et hd
hd
et screen
speed
et premium
hd
et premium
price
en fonction d'autres variables, mais prenant en compte plus de trois variablesanscombe
¶Représenter sur un même graphique (avec un découpage donc) les quatre séries des données anscombe
, toujours avec bokeh
et seaborn
.
anscombe = data("anscombe")
anscombe