Travaux pratiques - Classification automatique avec k-means¶
(la nouvelle version de cette séance, utilisant l’API DataFrame)
Références externes utiles :
Nous travaillerons lors de cette séance sur des données générées lors de la séance de travaux pratiques. Vous aurez à traiter ensuite les données Spambase Data Set issues de l’archive de l’UCI. Nous vous incitons à regarder sur le site de l’UCI des explications plus détaillées concernant ces données, notamment la signification des variables et les classes auxquelles appartiennent les données.
Ouvrez une fenêtre terminal et entrez
[cloudera@quickstart ~]$ export PATH="$PATH:/usr/lib/spark/bin" [cloudera@quickstart ~]$ mkdir -p tpkmeans/data [cloudera@quickstart ~]$ cd tpkmeans [cloudera@quickstart tpkmeans]$ spark-shell
Importation des librairies nécessaires¶
Entrez
scala> import org.apache.spark.mllib.clustering.KMeans scala> import org.apache.spark.mllib.linalg.Vectors scala> import org.apache.spark.mllib.util.KMeansDataGenerator
Génération des données¶
Nous nous servirons de KMeansDataGenerator.generateKMeansRDD
pour obtenir les données de travail. Cette méthode choisit d’abord k centres de groupes à partir d’une loi normale \(d\)-dimensionnelle, d’écart-type \(r\) et ensuite crée autour de chaque centre un groupe à partir d’une loi normale \(d\)-dimensionnelle d’écart-type 1. Les paramètres d’appel sont :
sc
: leSparkContext
concerné
numPoints
: le nombre total de données générées
k
: le nombre de centres (donc de groupes dans les données générées)
d
: la dimension des données
r
: écart-type pour la loi normale qui génère les centres
numPartitions
: nombre de partitions pour le RDD généré (2 par défaut)
Nous générerons 1000 données tridimensionnelles dans 5 groupes en utilisant :
// Générer les données scala> val donneesGenerees = KMeansDataGenerator.generateKMeansRDD(sc, 1000, 5, 3, 5, 1) scala> val donnees = donneesGenerees.map(s => Vectors.dense(s)).cache() scala> donnees.take(2) // Enregistrer les données dans un fichier texte scala> val donneesTxt = donnees.map(l => l.toString.filter(c => c != '[' & c != ']')) scala> donneesTxt.saveAsTextFile("file:///home/cloudera/tpkmeans/data/donnees")
numPartitions
a été fixé ici à 1 pour faciliter l’enregistrement des fichiers à visualiser. donneesGenerees
est de type RDD[Array]
, nous le transformons en donnees
de type RDD[Vector]
exigé par l’implémentation de k-means.
K-means avec initialisation par K-means||¶
Spark MLlib propose une implémentation de l’algorithme de classification automatique k-means. L’initialisation des centres est réalisée par l’algorithme parallèle k-means||, vu aussi en cours, avec 5 itérations (initializationSteps: 5
, peut être modifié avec KMeans.setInitializationSteps
).
- La classification est obtenue en appelant
KMeans.train
, avec les paramètres suivants : data
: données à classifier, sous forme deRDD[Vector]
k
: nombre de groupes (clusters)maxIterations
: nombre maximal d’itérations ; arrêt de l’exécution lorsque les centres sont stabilisés (àepsilon: 1e-4
près) oumaxIterations
est atteint ;epsilon
peut être modifié en appelantKMeans.epsilon
runs
: nombre d’exécutions (1 par défaut) ; c’est le meilleur modèle qui est retournéinitializationMode
: mode d’initialisation des centres, soitrandom
soitk-means||
(par défaut)seed
: initialisation du générateur de nombres aléatoires
Pour réaliser la classification automatique entrez dans spark-shell
les commandes suivantes :
// Appliquer k-means scala> val nbClusters = 5 scala> val nbIterations = 200 scala> val clusters = KMeans.train(donnees, nbClusters, nbIterations) // Evaluer la classification par la somme des inerties intra-classe scala> val siic1 = clusters.computeCost(donnees) // Trouver l'indice de groupe pour chaque donnée scala> val indices = clusters.predict(donnees) // Enregistrer les indices dans un fichier texte scala> indices.saveAsTextFile("file:///home/cloudera/tpkmeans/data/indices")
Visualisation des résultats¶
Dans cette séance nous visualiserons les données à l’aide de gnuplot
(installé dans la séance précédente). Vous pouvez vous servir d’autres outils (comme matplotlib
ou ggplot2
) si vous les maîtrisez déjà ; il vous faudra toutefois les installer.
Pour préparer la visualisation, il est nécessaire de concaténer les lignes du fichier de données et les lignes du fichier d’indices. Nous le ferons directement dans une fenêtre terminal :
[cloudera@quickstart ~]$ cd /home/cloudera/tpkmeans/data [cloudera@quickstart data]$ paste --delimiters="," donnees/part-00000 indices/part-00000 > donneesGnuplot.txt
Nous utiliserons cette fois gnuplot
à l’aide de commandes en ligne. Pour cela, ouvrez une nouvelle fenêtre terminal, placez-vous dans le répertoire /home/cloudera/tpkmeans
et lancez gnuplot
:
[cloudera@quickstart ~]$ cd /home/cloudera/tpkmeans [cloudera@quickstart spark]$ gnuplot gnuplot>
Entrez ensuite les commandes suivantes dans la fenêtre gnuplot
(après l’invite gnuplot>
) :
gnuplot> set datafile separator ',' gnuplot> set palette defined ( 0 "red", 1 "orange", 2 "brown", 3 "green", 4 "blue" ) gnuplot> splot "/home/cloudera/tpkmeans/data/donneesGnuplot.txt" using 1:2:3:4 with points lc palette
Nous avons d’abord indiqué à gnuplot
que le séparateur entre données d’une même ligne était la virgule (et non l’espace, séparateur par défaut), ensuite nous avons défini une palette permettant de donner à chaque point une couleur qui indique le groupe auquel il appartient et enfin nous avons appelé la fonction splot
en lui indiquant que les données tridimensionnelles à afficher étaient suivies d’une quatrième dimension correspondant à la couleur du point.
Vous pouvez faire tourner le graphique en maintenant appuyé le bouton gauche de la souris et en déplaçant le pointeur dans la fenêtre graphique.
Questions¶
Question :
Réalisez une nouvelle fois la classification des mêmes données avec k-means en 5 groupes. Visualisez les résultats en ouvrant une autre fenêtre terminal et en lançant gnuplot
dans cette fenêtre (afin de conserver la première fenêtre de visualisation). Que constatez-vous ?
Question :
Réalisez deux fois la classification des mêmes données avec k-means en 5 groupes mais avec une initialisation random
plutôt que k-means||
. Visualisez les résultats en ouvrant à chaque fois une autre fenêtre terminal et en lançant gnuplot
dans cette fenêtre (afin de conserver toutes les fenêtres de visualisation). Que constatez-vous ?
Question :
Réalisez la classification des mêmes données avec k-means et une initialisation k-means||
en 4 groupes et ensuite en 6 groupes. Visualisez à chaque fois les résultats. Que constatez-vous ?
Question :
Multipliez par 3 les données sur une des dimensions initiales. Réalisez la classification des nouvelles données avec k-means (et initialisation par k-means||
) en 5 groupes. Visualisez les résultats. Que constatez-vous ?
Question :
Réalisez la classification des données Spambase Data Set issues de l’archive de l’UCI. Comment pré-traiter les données et pourquoi ? Combien de groupes rechercher ? Visualisez ensuite leurs projections sur des groupes de 3 variables.