Principe
En Data science ou Data engineering, il est courant de devoir partitionner un groupe de populations selon plusieurs variables. Par exemple, on souhaite identifier un groupe de populations jeune dont le poids et la taille sont élevés. Dans cet article, nous vous proposons d’utiliser TensorFlow et Python pour traiter cette problématique.
Très généralement, pour ce cas d’usage, on va utiliser l’algorithme des K-Means (ou des K moyennes en français). Cet algorithme de machine learning, non supervisé, est utilisé pour partitionner un jeu de données en N groupes ou clusters selon un principe d’optimisation discrète (Plus d’infos ici : https://fr.wikipedia.org/wiki/K-moyennes).
Revenons à un exemple concret simple. J’ai à disposition une population d’individus plutôt conséquente, sur laquelle je souhaite identifier un groupe de personnes ayant des caractéristiques communes. Par exemple, nous souhaitons identifier une population jeune, dont le poids et la taille sont élevés. Une fois ce groupe identifié, on sera en mesure d’y appliquer d’autres méthodes de sélection plus ciblées, ou d’éliminer des groupes dont les caractéristiques ne répondent pas aux objectifs d’analyses fixés.
Cet exemple est donné à titre d’exemple. En effet, il est tou d’abord assez peu représentatif de la réalité. Le K-Means peut donner des résultats un peu étranges notamment en fonction de la distribution des données qui est, ici totalement aléatoire. De plus, les variables ne sont pas corrélées.
Environnement technique: TensorFlow, Python et un peu de Cloud ?
Pour réaliser ce test, nous allons avoir besoin d’un environnement technique dont les caractéristiques sont données ci-dessous.
- Python 3.6
Pour écrire cette implémentation, nous allons utiliser Python (dans sa version 3.6). Python est le langage approprié pour de nombreuses problématiques de Data Science notamment. De plus, c’est un langage riche en librairies. Dans notre exemple, nous avons utilisé les librairies suivantes :
- Numpy pour la représentation matricielle et le calcul scientifique
- Matplotlib pour la représentation graphique des résultats
- Mpl_toolkits.mplot3d pour la représentation 3D
- os pour le positionnement de variables d’environnement visant à rendre Numpy et Tensorflow plus ou moins verbeux.
et Tensorflow …
- Tensorflow
Tensorflow est une librairie de Machine Learning (et surtout de Deep Learning) développée par Google. Son intégration avec Python est très simple, et ses APIs richement documentées (https://www.tensorflow.org/api_docs/). De plus, c’est une librairie entièrement interfaçable avec les GPU. Pour de simples problématiques de Machine Learning, il faudra installer la librairie CuDA, et CuDnn si vous souhaitez développer un modèle basé sur un réseau de neurones.
- Cloud
Si le volume de données en entrée est conséquent, il est conseillé de disposer d’une grosse puissance de calcul. Dans ce cas, une plateforme optimisée pour le machine learning de type GCP ou Amazon SageMaker sera un choix incontournable.
Les différentes parties du code
Configuration et initialisation des données
La première partie du script est assez simple, elle consiste en une déclaration des packages et des variables visant à rendre Numpy plus verbeux, et Tensorflow un peu moins verbeux (on se retrouve sinon avec tout le debug lié au GPU)
1 2 3 4 5 6 7 8 9 10 11 |
import numpy as np import tensorflow as tf import os import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D # Debug and output config # # Remove TensorFlow output for GPU blabla os.environ["TF_CPP_MIN_LOG_LEVEL"]="2" # # Print full content of numpy arrays np.set_printoptions(threshold=np.nan) |
Ensuite, nous avons utilisé les fonctions de randomisation offertes par Numpy pour initialiser un tableau de 3 colonnes représentant nos 3 variables que sont le poids, l’âge et la taille (ces données sont là pour l’exemple, la réalité est toute autre 😉 ).
C’est également dans cette partie du code que l’on définit la taille de notre échantillon, ici 1000. Si cet exemple avait été constituée de véritables données, l’initialisation aurait été réalisée à partir de différentes sources (fichiers, bases relationnelles etc.)
1 2 3 4 5 6 7 |
# Initialization num_points = 1000 dimensions = 3 points=np.empty([num_points,dimensions],dtype=float) points[:,0] = np.random.triangular(50,75,130,num_points) #Weight points[:,1] = np.random.triangular(18,40,105,num_points) #Age points[:,2] = 70*np.random.random_sample(num_points)+130 #Height |
Déclaration du modèle et entrainement
La partie suivante est importante car elle va définir une fonction qui va transformer notre source de données (en l’occurrence notre tableau) en un tensor (objet de base dans tensorflow) dont le nombre de cycles d’évaluation va être positionné à 1.
1 2 |
def input_fn(): return tf.train.limit_epochs(tf.convert_to_tensor(points, dtype=tf.float32), num_epochs=1) |
Nous abordons la partie principale du script, dans laquelle nous allons successivement déclarer notre Estimator de type Kmeans, le nombre de clusters désirés. Cette déclaration sera suivie par l’entrainement à proprement dit. L’entrainement d’un KMeans consiste à déplacer les centres des clusters pour les rapprocher au plus près des points ou plutôt du triplet de variables représenté par notre point. Bien évidemment, plus il y aura de cycles et plus la segmentation sera correctement réalisée. Ceci s’observe assez facilement par le scoring qui, au dernier tour d’entrainement, n’évolue plus trop (voire plus du tout).
1 2 3 4 5 6 7 8 9 |
# Kmeans Estimator definition num_clusters = 15 kmeans = tf.contrib.factorization.KMeansClustering(num_clusters=num_clusters, use_mini_batch=False) # train num_iterations = 20 for _ in range(num_iterations): kmeans.train(input_fn) print('Training ... score:', kmeans.score(input_fn)) |
Notons que dans cette partie de code, on peut facilement obtenir les coordonnées des centres de cluster en invoquant la fonction cluster_centers() de l’objet KMeansClustering.
La dernière partie du traitement (hors affichage des résultats) se réalise en récupérant les indexs du cluster. En somme, on associe un point à un cluster identifié par un nombre.
1 2 |
# map the input points to their clusters cluster_indices = list(kmeans.predict_cluster_index(input_fn)) |
Voilà, le Kmeans est terminé. Il est temps de passer à l’affichage des résultats.
Affichage et représentation des résultats
Dans un premier temps, l’affichage est réalisé sous format texte dans la sortie standard:
1 2 3 |
# print results to stdout for i, point in enumerate(points): print("point = ", point," cluster =", cluster_indices[i]) |
Ce qui nous donne ce genre de résultats (très peu intuitifs 😉 ):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
point = [ 77.79233762 61.45190957 188.60922907] cluster = 9 point = [ 94.68954154 58.51184045 159.44953758] cluster = 1 point = [ 97.41650914 31.0531524 181.93722073] cluster = 10 point = [ 87.65028012 26.66838664 144.44581754] cluster = 5 point = [103.77178359 46.81565704 124.77128091] cluster = 0 point = [ 62.10549909 75.86581566 180.13530464] cluster = 9 point = [ 71.08844457 43.51220485 159.53461047] cluster = 6 point = [ 68.70869713 92.81917456 130.26556031] cluster = 11 point = [ 96.97357616 22.84714326 126.80535865] cluster = 5 .../... point = [113.11362688 28.32345754 131.6451451 ] cluster = 0 point = [ 60.80444027 31.32558042 173.07309765] cluster = 7 point = [ 89.57539699 33.89327285 133.5756532 ] cluster = 5 point = [ 98.04675146 26.64530605 142.21844414] cluster = 0 point = [ 65.42652561 82.31199062 151.03939098] cluster = 12 point = [ 82.82402273 87.82845737 134.9964642 ] cluster = 11 |
Dans un second temps, l’affichage des résultats est réalisé dans un graphe 3D (chaque axe représente une variable) et chaque index de cluster est associé à une couleur pour une identification plus intuitive:
1 2 3 4 5 6 7 8 |
# plotting results into a nice 3D graph fig = plt.figure() ax = Axes3D(fig) sc=ax.scatter3D(xs=points[:,0], ys=points[:,1], zs=points[:,2], c=cluster_indices, s=15, marker='H') ax.set_xlabel('Weight') ax.set_ylabel('Age') ax.set_zlabel('Height') plt.show() |
Le résultat ressemblera à cela (ici on cible le cluster représenté en bleu) :
En conclusion
Pour conclure ce billet, on peut voir que l’association Python et Tensorflow permet une implémentation rapide d’algorithmes de Machine Learning (ici le Kmeans)… visualisation incluse.
Comme rappelé précedemment, cet article a été écrit dans le but de voir comment on peut partitionner des datasets conséquents, les visualiser, dans le but par exemple d’éliminer les données peu utiles dans l’objectif d’analyse que l’on s’est fixé.