Python
¶Nous utilisons dans ce TP le module scikit-learn
, dédié au Machine Learning. Pour mieux la découvrir, nous allons réaliser une étude de cas, avec les données iris
.
Dans cette étude, nous allons chercher à savoir s'il existe différentes sous-espèces d'iris. Pour cela, nous allons procéder par étapes ::
Dans un premier temps, il va nous falloir importer les données (iris
) que nous allons utiliser (via la librairie pydataset
). Nous allons aussi utiliser d'autres librairies (telles que seaborn
, numpy
, matplotlib
et pandas
).
Nous importerons les éléments de scikit-learn
(module sklearn
) au fur et à mesure.
import numpy
import pandas
import matplotlib.pyplot as plt
import seaborn
seaborn.set_style("white")
%matplotlib inline
Pour rappel, la table se présente comme ceci :
iris = pandas.read_csv("Iris.txt", sep="\t")
iris.head()
Dans le sous-module decomposition
, nous allons importer la fonction PCA()
. Le fonctionnement de celle-ci est similaire à toutes les autres dans scikit-learn
.
pca
) qui va contenir le résultat de l'ACP. Dans la fonction PCA()
, on pourra indiquer les paramètres tels que le nombre de composants à retenir (n_components
) ou la méthode de calcul (svd_solver
).fit()
de l'objet précédemment créé. Dans cette fonction, nous devons donc passer les données à utiliser.Si l'on souhaite une ACP normée, il nous faut standardiser les données en amont, avec la fonction scale()
du sous-module preprocessing
(importée aussi ici). Bien évidemment, il ne faut passer que des variables quantitatives.
from sklearn.decomposition import PCA
from sklearn.preprocessing import scale
pca = PCA()
pca.fit(scale(iris[iris.columns[:4]]))
L'objet pca
comprend maintenant un certain nombre d'objets et de fonctions. Le premier objet est le tableau des variances expliquées (explained_variance_
) par chaque dimension, et le ratio (proportion) de variance expliquée par dimension (explained_variance_ratio_
).
print(pca.explained_variance_)
print(pca.explained_variance_ratio_)
Bien évidemment, il est possible (et préférable) de faire un tableau récapitulatif, avec les valeurs propres, les proportions de variance expliquée simples et cumulées. Voici un petit code permettant de faire ceci.
eig = pandas.DataFrame(
{
"Dimension" : ["Dim" + str(x + 1) for x in range(4)],
"Valeur propre" : pca.explained_variance_,
"% variance expliquée" : numpy.round(pca.explained_variance_ratio_ * 100),
"% cum. var. expliquée" : numpy.round(numpy.cumsum(pca.explained_variance_ratio_) * 100)
},
columns = ["Dimension", "Valeur propre", "% variance expliquée", "% cum. var. expliquée"]
)
eig
L'idée est de représenter graphiquement ces proportions de variances expliquées (qu'on passe en pourcentage par convenance).
g_eig = seaborn.barplot(x = "Dimension",
y = "% variance expliquée",
palette = ["lightseagreen"],
data = eig)
g_eig.set(ylabel = "Variance expliquée (%)")
g_eig.figure.suptitle("Variance expliquée par dimension")
plt.axhline(y = 25, linewidth = .5, color = "dimgray", linestyle = "--") # 25 = 100 / 4 (nb dimensions)
plt.text(3.25, 26, "25%")
On remarque ici qu'avec seulement deux dimensions suffisent à expliquer 96 % de la variance des données. Nous allons maintenant calculer les coordonnées des iris sur les dimensions, avec la fonction transform()
de l'objet pca
.
iris_pca = pca.transform(iris[iris.columns[:4]])
Afin de manipuler plus facilement l'objet obtenu par la suite, nous allons créer un DataFrame
pandas
en ne prenant que les deux premières dimensions, ainsi que les espèces.
# Transformation en DataFrame pandas
iris_pca_df = pandas.DataFrame({
"Dim1" : iris_pca[:,0],
"Dim2" : iris_pca[:,1],
"Species" : iris.Species
})
# Résultat (premières lignes)
iris_pca_df.head()
Il est maintenant possible de représenter les données sur le premier plan factoriel, en ajoutant bien évidemment l'information sur les espèces.
g_pca = seaborn.lmplot("Dim1", "Dim2", hue = "Species", data = iris_pca_df, fit_reg = False)
g_pca.set(xlabel = "Dimension 1 (73%)", ylabel = "Dimension 2 (23 %)")
g_pca.fig.suptitle("Premier plan factoriel")
Il est aussi possible de différencier l'affichage de ce premier plan par espèce, grâce à l'option col
de lmplot()
g_pca2 = seaborn.lmplot("Dim1", "Dim2", hue = "Species", col = "Species", col_wrap = 2, data = iris_pca_df, fit_reg = False)
g_pca2.set(xlabel = "Dimension 1 (73%)", ylabel = "Dimension 2 (23 %)")
DBSCAN
est un algorithme de classification non supervisée, basé sur la densité. Il est intéressant car il ne nécessite pas de connaître le nombre de classes, mais une estimation de la densité (globale) des données. En effet, les points proches (distance inférieure à $\varepsilon$) sont consiédérés dans la même classe. Si toutefois cette classe comporte au moins un cetain nombre de points au final. Si ce n'est pas le cas, les points sont considérés comme outliers et mis à part.
Nous utilisons ici la fonction DBSCAN()
du sous-module cluster
. Celle-ci peut prendre en paramètre, entre autres, la valeur de $\varepsilon$ (eps
, .5
par défaut) et le nombre minimal d'objets dans une classe (min_samples
, 5
par défaut).
Puis nous ajustons les données standardisées (pour ne pas donner plus d'influences à une variable qu'à une autre).
from sklearn.cluster import DBSCAN
db = DBSCAN(eps = .6, min_samples = 3)
db.fit(scale(iris[iris.columns[:4]]))
Les classes dont contenues dans l'objet labels_
de db
. On a pour chaque individu sa classe (de $0$ à $K-1$ pour $K$ classes obtenues). Les outliers sont étiquettés $-1$ .
db.labels_
On peut faire un tableau récapitulatif des effectifs par classes.
eff = numpy.unique(db.labels_, return_counts = True)
pandas.DataFrame({
"Classe" : eff[0],
"Effectif" : eff[1]
})
Pour la représentation des données, on ajoute ces labels de classe aux projections des iris sur le premier plan factoriel.
iris_pca_db = iris_pca_df.assign(Labels = db.labels_)
On peut ainsi représenter les données en fonction des espèces et des classes obtenues.
seaborn.lmplot("Dim1", "Dim2", hue = "Labels", col = "Species", data = iris_pca_db, fit_reg = False)
On peut aussi splitter le graphique en ligne pour chaque classe.
seaborn.lmplot("Dim1", "Dim2", hue = "Labels", col = "Species", row = "Labels", data = iris_pca_db, fit_reg = False)
Nous allons travailler ici sur les données de température mondiale HadCRUT4, fournies par Climate Research Unit. Vous trouverez plus d’informations sur ces données sur ce lien. Nous avons ici l’historique des anomalies moyennes mensuelles et annuelles depuis 1850, au niveau mondial, par rapport à la période 1961-1990.
Le code ci-dessous télécharge directement les dernières données disponibles et les met dans un DataFrame dont vous avez un aperçu en dessous (en supprimant l’année 2019, incomplète).
had = pandas.read_csv("https://crudata.uea.ac.uk/cru/data/temperature/HadCRUT4-gl.dat", header=None)
donnees = pandas.DataFrame(
[list(map(lambda v: float(v), filter(lambda v: v!= "", h.split(" ")))) for h in had[0][::2]],
columns = ["Year", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "Annual"]
)
donnees.tail()
Vous devez donc réaliser les étapes suivantes :
La banque mondiale fournit un grand nombre de données, dont des indicateurs de gouvernance au niveau mondial (voir ici). Le code ci-dessous importe les données du fichier WGI_Data.csv (que vous devez donc télécharger) pour les importer. Les informations concernant la définition des indicateurs et leur source se trouvent dans le fichier WGI_Definition and Source.csv.
wgi_one = pandas.read_csv("WGI_Data.csv")
wgi_one.head()
wgi_bis = wgi_one[["Country Name", "Series Code", "Value"]][wgi_one.Value != ".."]
wgi_ter = wgi_bis.astype({"Value": float})
wgi = wgi_ter.pivot_table(values = "Value", index = "Country Name", columns = "Series Code")
wgi.head()
Vous devez donc réaliser les étapes suivantes :
eps