Guide définitif du clustering hiérarchique avec Python et Scikit-Learn PlatoBlockchain Data Intelligence. Recherche verticale. Aï.

Guide définitif du clustering hiérarchique avec Python et Scikit-Learn

Introduction

Dans ce guide, nous nous concentrerons sur la mise en œuvre des Algorithme de clustering hiérarchique avec Scikit-Learn résoudre un problème de commercialisation.

Après avoir lu le guide, vous comprendrez :

  • Quand appliquer le clustering hiérarchique
  • Comment visualiser l'ensemble de données pour comprendre s'il est adapté au clustering
  • Comment pré-traiter les fonctionnalités et concevoir de nouvelles fonctionnalités basées sur l'ensemble de données
  • Comment réduire la dimensionnalité de l'ensemble de données à l'aide de l'ACP
  • Comment utiliser et lire un dendrogramme pour séparer les groupes
  • Quelles sont les différentes méthodes de liaison et les métriques de distance appliquées aux dendrogrammes et aux algorithmes de clustering
  • Quelles sont les stratégies de clustering agglomératif et diviseur et comment elles fonctionnent
  • Comment implémenter le clustering hiérarchique agglomératif avec Scikit-Learn
  • Quels sont les problèmes les plus fréquents liés aux algorithmes de clustering et comment les résoudre

Remarque: Vous pouvez télécharger le notebook contenant tout le code de ce guide ici.

motivation

Imaginez un scénario dans lequel vous faites partie d'une équipe de science des données qui s'interface avec le service marketing. Le marketing recueille des données d'achat des clients depuis un certain temps, et ils veulent comprendre, sur la base des données collectées, s'il y a similitudes entre les clients. Ces similitudes divisent les clients en groupes et le fait d'avoir des groupes de clients aide à cibler les campagnes, les promotions, les conversions et à établir de meilleures relations avec les clients.

Existe-t-il un moyen d'aider à déterminer quels clients sont similaires ? Combien d'entre eux appartiennent au même groupe ? Et combien y a-t-il de groupes différents ?

Une façon de répondre à ces questions est d'utiliser un regroupement algorithme, tel que K-Means, DBSCAN, Hierarchical Clustering, etc. En termes généraux, les algorithmes de clustering trouvent des similitudes entre les points de données et les regroupent.

Dans ce cas, nos données marketing sont assez petites. Nous avons des informations sur seulement 200 clients. Considérant l'équipe marketing, il est important que nous puissions leur expliquer clairement comment les décisions ont été prises en fonction du nombre de clusters, leur expliquant ainsi comment fonctionne réellement l'algorithme.

Étant donné que nos données sont petites et que l'explicabilité est un facteur majeur, nous pouvons tirer parti Classification hiérarchique pour résoudre ce problème. Ce processus est également connu sous le nom de Analyse de clustering hiérarchique (HCA).

L'un des avantages de HCA est qu'il est interprétable et fonctionne bien sur de petits ensembles de données.

Une autre chose à prendre en considération dans ce scénario est que HCA est un sans surveillance algorithme. Lors du regroupement des données, nous n'aurons aucun moyen de vérifier que nous identifions correctement qu'un utilisateur appartient à un groupe spécifique (nous ne connaissons pas les groupes). Il n'y a pas d'étiquettes auxquelles nous pouvons comparer nos résultats. Si nous avons correctement identifié les groupes, cela sera ensuite confirmé par le service marketing au jour le jour (tel que mesuré par des métriques telles que le retour sur investissement, les taux de conversion, etc.).

Maintenant que nous avons compris le problème que nous essayons de résoudre et comment le résoudre, nous pouvons commencer à jeter un œil à nos données !

Brève analyse exploratoire des données

Remarque: Vous pouvez télécharger le jeu de données utilisé dans ce guide ici.

Après avoir téléchargé l'ensemble de données, notez qu'il s'agit d'un CSV (valeurs séparées par des virgules) fichier appelé shopping-data.csv. Pour faciliter l'exploration et la manipulation des données, nous allons les charger dans un DataFrame en utilisant Panda :

import pandas as pd


path_to_file = 'home/projects/datasets/shopping-data.csv'
customer_data = pd.read_csv(path_to_file)

Le marketing a déclaré avoir collecté 200 dossiers clients. Nous pouvons vérifier si les données téléchargées sont complètes avec 200 lignes en utilisant le shape attribut. Il nous dira combien de lignes et de colonnes nous avons, respectivement :

customer_data.shape

Cela se traduit par:

(200, 5)

Super! Nos données sont complètes avec 200 lignes (dossiers clients) et nous avons aussi 5 colonnes (caractéristiques). Pour voir quelles caractéristiques le service marketing a collectées auprès des clients, nous pouvons voir les noms de colonne avec le columns attribut. Pour ce faire, exécutez :

customer_data.columns

Le script ci-dessus renvoie :

Index(['CustomerID', 'Genre', 'Age', 'Annual Income (k$)',
       'Spending Score (1-100)'],
      dtype='object')

Ici, on voit que le marketing a généré une CustomerID, a réuni le Genre, Age, Annual Income (en milliers de dollars) et un Spending Score allant de 1 à 100 pour chacun des 200 clients. Lorsqu'on leur a demandé des éclaircissements, ils ont dit que les valeurs du Spending Score signifient la fréquence à laquelle une personne dépense de l'argent dans un centre commercial sur une échelle de 1 à 100. En d'autres termes, si un client a un score de 0, cette personne ne dépense jamais d'argent, et si le score est de 100, nous venons de repérer le le plus dépensier.

Examinons rapidement la distribution de ce score pour inspecter les habitudes de dépenses des utilisateurs dans notre ensemble de données. C'est là que les Pandas hist() méthode vient pour aider:

customer_data['Spending Score (1-100)'].hist()

img

En regardant l'histogramme, nous voyons que plus de 35 clients ont des scores entre 40 ainsi que 60, alors moins de 25 ont des scores entre 70 ainsi que 80. Ainsi, la plupart de nos clients sont dépensiers équilibrés, suivis des dépensiers modérés à élevés. On peut aussi voir qu'il y a une ligne après 0, à gauche de la distribution, et une autre ligne avant 100, à droite de la distribution. Ces espaces vides signifient probablement que la distribution ne contient pas de non-dépensiers, ce qui aurait un score de 0, et qu'il n'y a pas non plus de grands dépensiers avec un score de 100.

Pour vérifier si cela est vrai, nous pouvons regarder les valeurs minimales et maximales de la distribution. Ces valeurs peuvent être facilement trouvées dans le cadre des statistiques descriptives, nous pouvons donc utiliser les describe() méthode pour comprendre les autres distributions de valeurs numériques :


customer_data.describe().transpose()

Cela nous donnera un tableau à partir duquel nous pourrons lire les distributions des autres valeurs de notre ensemble de données :

 						count 	mean 	std 		min 	25% 	50% 	75% 	max
CustomerID 				200.0 	100.50 	57.879185 	1.0 	50.75 	100.5 	150.25 	200.0
Age 					200.0 	38.85 	13.969007 	18.0 	28.75 	36.0 	49.00 	70.0
Annual Income (k$) 		200.0 	60.56 	26.264721 	15.0 	41.50 	61.5 	78.00 	137.0
Spending Score (1-100) 	200.0 	50.20 	25.823522 	1.0 	34.75 	50.0 	73.00 	99.0

Notre hypothèse est confirmée. La min valeur de la Spending Score is 1 et le maximum est 99. Nous n'avons donc pas 0 or 100 les dépensiers. Jetons ensuite un coup d'œil aux autres colonnes de la transposition describe table. Quand on regarde le mean ainsi que std colonnes, nous pouvons voir que pour Age le mean is 38.85 et par std est d'environ 13.97. Il en est de même pour Annual Income, avec une mean of 60.56 ainsi que std 26.26, Et pour Spending Score avec une mean of 50 ainsi que std of 25.82. Pour toutes les fonctionnalités, le mean est loin de l'écart-type, ce qui indique nos données ont une grande variabilité.

Pour mieux comprendre comment nos données varient, traçons les Annual Income Distribution:

customer_data['Annual Income (k$)'].hist()

Ce qui nous donnera :

img

Remarquez dans l'histogramme que la plupart de nos données, plus de 35 clients, sont concentrées près du nombre 60, sur notre mean, sur l'axe horizontal. Mais que se passe-t-il lorsque nous nous dirigeons vers les extrémités de la distribution ? En allant vers la gauche, à partir de la moyenne de 60.560 $, la prochaine valeur que nous rencontrerons est de 34.300 $ – la moyenne (60.560 $) moins la variation standard (26.260 $). Si nous nous éloignons plus à gauche de notre distribution de données, une règle similaire s'applique : nous soustrayons la variation standard (26.260 $) de la valeur actuelle (34.300 $). Par conséquent, nous rencontrerons une valeur de 8.040 $. Remarquez comment nos données sont passées rapidement de 60 8 $ à 26.260 XNUMX $. Il « saute » de XNUMX XNUMX $ à chaque fois – ce qui varie beaucoup, et c'est pourquoi nous avons une telle variabilité.

img

La variabilité et la taille des données sont importantes dans l'analyse de clustering car les mesures de distance de la plupart des algorithmes de clustering sont sensibles à l'ampleur des données. La différence de taille peut modifier les résultats du regroupement en rendant un point plus proche ou plus éloigné d'un autre qu'il ne l'est en réalité, ce qui fausse le regroupement réel des données.

Jusqu'à présent, nous avons vu la forme de nos données, certaines de ses distributions et des statistiques descriptives. Avec Pandas, nous pouvons également lister nos types de données et voir si toutes nos 200 lignes sont remplies ou en ont null valeurs:

customer_data.info()

Cela se traduit par:

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 200 entries, 0 to 199
Data columns (total 5 columns):
 #   Column                  Non-Null Count  Dtype 
---  ------                  --------------  ----- 
 0   CustomerID              200 non-null    int64 
 1   Genre                   200 non-null    object
 2   Age                     200 non-null    int64 
 3   Annual Income (k$)      200 non-null    int64 
 4   Spending Score (1-100)  200 non-null    int64 
dtypes: int64(4), object(1)
memory usage: 7.9+ KB

Ici, on voit qu'il n'y a pas null valeurs dans les données et que nous n'avons qu'une seule colonne catégorielle - Genre. A ce stade, il est important que nous ayons en tête quelles fonctionnalités semblent intéressantes à ajouter au modèle de clustering. Si nous voulons ajouter la colonne Genre à notre modèle, nous devrons transformer ses valeurs de catégorique à numérique.

Voyons comment Genre est rempli en jetant un coup d'œil rapide aux 5 premières valeurs de nos données :

customer_data.head() 

Cela se traduit par:

    CustomerID 	Genre 	Age 	Annual Income (k$) 	Spending Score (1-100)
0 	1 			Male 	19 		15 					39
1 	2 			Male 	21 		15 					81
2 	3 			Female 	20 		16 					6
3 	4 			Female 	23 		16 					77
4 	5 			Female 	31 		17 					40

Il semble qu'il n'a que Female ainsi que Male catégories. Nous pouvons en être sûrs en examinant ses valeurs uniques avec unique:

customer_data['Genre'].unique()

Cela confirme notre hypothèse :

array(['Male', 'Female'], dtype=object)

Jusqu'à présent, nous savons que nous n'avons que deux genres, si nous prévoyons d'utiliser cette fonctionnalité sur notre modèle, Male pourrait être transformé en 0 ainsi que Female à 1. Il est également important de vérifier la proportion entre les genres, pour voir s'ils sont équilibrés. Nous pouvons le faire avec le value_counts() méthode et son argument normalize=True pour afficher le pourcentage entre Male ainsi que Female:

customer_data['Genre'].value_counts(normalize=True)

Cela produit:

Female    0.56
Male      0.44
Name: Genre, dtype: float64

Nous avons 56 % de femmes dans l'ensemble de données et 44 % d'hommes. La différence entre eux n'est que de 16 %, et nos données ne sont pas 50/50 mais assez équilibré pour ne pas causer d'ennuis. Si les résultats étaient de 70/30, 60/40, il aurait peut-être été nécessaire de collecter plus de données ou d'employer une sorte de technique d'augmentation des données pour rendre ce rapport plus équilibré.

Jusqu'à présent, toutes les fonctionnalités sauf Age, ont été brièvement explorées. En quoi concerne Age, il est généralement intéressant de le diviser en bacs pour pouvoir segmenter les clients en fonction de leurs tranches d'âge. Si nous faisions cela, nous aurions besoin de transformer les catégories d'âge en un seul nombre avant de les ajouter à notre modèle. Ainsi, au lieu d'utiliser la catégorie 15-20 ans, on compterait le nombre de clients qu'il y a dans le 15-20 catégorie, et ce serait un nombre dans une nouvelle colonne appelée 15-20.

Conseils: Dans ce guide, nous ne présentons qu’une brève analyse exploratoire des données. Mais vous pouvez aller plus loin et vous devriez aller plus loin. Vous pouvez voir s’il existe des différences de revenus et des différences de notation en fonction du genre et de l’âge. Cela enrichit non seulement l’analyse, mais conduit à de meilleurs résultats de modèle. Pour approfondir l'analyse exploratoire des données, consultez le Chapitre EDA dans le "Prévision pratique du prix des maisons - Apprentissage automatique en Python" Projet guidé.

Après avoir conjecturé sur ce qui pourrait être fait avec à la fois catégorique – ou catégorique pour être – Genre ainsi que Age colonnes, appliquons ce qui a été discuté.

Variables d'encodage et ingénierie des fonctionnalités

Commençons par diviser le Age en groupes qui varient en 10, de sorte que nous avons 20-30, 30-40, 40-50, et ainsi de suite. Puisque notre plus jeune client a 15 ans, nous pouvons commencer à 15 ans et terminer à 70 ans, soit l'âge du client le plus âgé dans les données. Commençant à 15 et se terminant à 70, nous aurions des intervalles de 15-20, 20-30, 30-40, 40-50, 50-60 et 60-70.

Pour regrouper ou coffre Age valeurs dans ces intervalles, nous pouvons utiliser les Pandas cut() méthode pour les découper en bacs, puis affecter les bacs à un nouveau Age Groups colonne:

intervals = [15, 20, 30, 40, 50, 60, 70]
col = customer_data['Age']
customer_data['Age Groups'] = pd.cut(x=col, bins=intervals)


customer_data['Age Groups'] 

Cela se traduit par:

0      (15, 20]
1      (20, 30]
2      (15, 20]
3      (20, 30]
4      (30, 40]
         ...   
195    (30, 40]
196    (40, 50]
197    (30, 40]
198    (30, 40]
199    (20, 30]
Name: Age Groups, Length: 200, dtype: category
Categories (6, interval[int64, right]): [(15, 20] < (20, 30] < (30, 40] < (40, 50] < (50, 60] < (60, 70]]

Notez que lorsque vous regardez les valeurs de colonne, il y a aussi une ligne qui spécifie que nous avons 6 catégories et affiche tous les intervalles de données regroupés. De cette façon, nous avons catégorisé nos données précédemment numériques et créé un nouveau Age Groups fonction.

Et combien de clients avons-nous dans chaque catégorie ? Nous pouvons rapidement savoir qu'en regroupant la colonne et en comptant les valeurs avec groupby() ainsi que count():

customer_data.groupby('Age Groups')['Age Groups'].count()

Cela se traduit par:

Age Groups
(15, 20]    17
(20, 30]    45
(30, 40]    60
(40, 50]    38
(50, 60]    23
(60, 70]    17
Name: Age Groups, dtype: int64

Il est facile de remarquer que la plupart des clients ont entre 30 et 40 ans, suivis des clients entre 20 et 30 ans, puis des clients entre 40 et 50 ans. C'est aussi une bonne information pour le service Marketing.

Pour le moment, nous avons deux variables catégorielles, Age ainsi que Genre, que nous devons transformer en nombres pour pouvoir les utiliser dans notre modèle. Il existe de nombreuses façons différentes de réaliser cette transformation - nous utiliserons les Pandas get_dummies() méthode qui crée une nouvelle colonne pour chaque intervalle et genre, puis remplit ses valeurs avec des 0 et des 1 - ce type d'opération est appelé encodage à chaud. Voyons à quoi ça ressemble:


customer_data_oh = pd.get_dummies(customer_data)

customer_data_oh 

Cela nous donnera un aperçu du tableau résultant :

img

Avec la sortie, il est facile de voir que la colonne Genre était divisé en colonnes - Genre_Female ainsi que Genre_Male. Lorsque le client est une femme, Genre_Female est égal à 1, et lorsque le client est un homme, cela équivaut à 0.

Également Age Groups colonne a été divisée en 6 colonnes, une pour chaque intervalle, comme Age Groups_(15, 20], Age Groups_(20, 30], etc. De la même façon que Genre, lorsque le client a 18 ans, le Age Groups_(15, 20] valeur est 1 et la valeur de toutes les autres colonnes est 0.

La avantage de l'encodage à chaud est la simplicité de représentation des valeurs de colonne, il est simple de comprendre ce qui se passe - alors que le désavantage est que nous avons maintenant créé 8 colonnes supplémentaires, pour résumer avec les colonnes que nous avions déjà.

 : Si vous avez un ensemble de données dans lequel le nombre de colonnes encodées à chaud dépasse le nombre de lignes, il est préférable d'utiliser une autre méthode d'encodage pour éviter les problèmes de dimensionnalité des données.

L'encodage à chaud ajoute également des 0 à nos données, ce qui les rend plus rares, ce qui peut poser problème pour certains algorithmes sensibles à la rareté des données.

Pour nos besoins de clustering, l'encodage à chaud semble fonctionner. Mais nous pouvons tracer les données pour voir s'il existe vraiment des groupes distincts à regrouper.

Tracé de base et réduction de la dimensionnalité

Notre ensemble de données comporte 11 colonnes et nous pouvons visualiser ces données de différentes manières. Le premier consiste à le tracer en 10 dimensions (bonne chance avec ça). Dix parce que le Customer_ID colonne n'est pas prise en compte. La seconde consiste à tracer nos caractéristiques numériques initiales, et la troisième consiste à transformer nos 10 caractéristiques en 2 - par conséquent, en effectuant une réduction de dimensionnalité.

Tracer chaque paire de données

Puisqu'il est un peu impossible de tracer 10 dimensions, nous allons opter pour la deuxième approche - nous allons tracer nos caractéristiques initiales. Nous pouvons en choisir deux pour notre analyse de clustering. Une façon de voir toutes nos paires de données combinées est avec un Seaborn pairplot():

import seaborn as sns


customer_data = customer_data.drop('CustomerID', axis=1)

sns.pairplot(customer_data)

Qui affiche :

img

En un coup d'œil, nous pouvons repérer les nuages ​​de points qui semblent avoir des groupes de données. Celui qui semble intéressant est le nuage de points qui combine Annual Income ainsi que Spending Score. Notez qu'il n'y a pas de séparation claire entre les autres nuages ​​de points variables. Tout au plus peut-on dire qu'il y a deux concentrations distinctes de points dans le Spending Score vs Age nuage de points.

Les deux diagrammes de dispersion consistant en Annual Income ainsi que Spending Score sont essentiellement les mêmes. Nous pouvons le voir deux fois car les axes x et y ont été échangés. En jetant un coup d'œil à l'un d'entre eux, nous pouvons voir ce qui semble être cinq groupes différents. Traçons juste ces deux caractéristiques avec un Seaborn scatterplot() pour regarder de plus près :

sns.scatterplot(x=customer_data['Annual Income (k$)'],
                y=customer_data['Spending Score (1-100)'])

img

En y regardant de plus près, on peut définitivement distinguer 5 groupes de données différents. Il semble que nos clients puissent être regroupés en fonction de leurs revenus annuels et de leurs dépenses. C'est un autre point pertinent dans notre analyse. Il est important que nous ne prenions en considération que deux caractéristiques pour regrouper nos clients. Toute autre information dont nous disposons à leur sujet n'entre pas dans l'équation. Cela donne un sens à l'analyse - si nous savons combien un client gagne et dépense, nous pouvons facilement trouver les similitudes dont nous avons besoin.

img

C'est génial! Jusqu'à présent, nous avons déjà deux variables pour construire notre modèle. Outre ce que cela représente, cela rend également le modèle plus simple, parcimonieux et plus explicable.

Consultez notre guide pratique et pratique pour apprendre Git, avec les meilleures pratiques, les normes acceptées par l'industrie et la feuille de triche incluse. Arrêtez de googler les commandes Git et en fait apprendre il!

Remarque: La science des données privilégie généralement des approches aussi simples que possible. Non seulement parce qu'il est plus facile à expliquer pour l'entreprise, mais aussi parce qu'il est plus direct - avec 2 fonctionnalités et un modèle explicable, il est clair ce que fait le modèle et comment il fonctionne.

Tracer des données après avoir utilisé PCA

Il semble que notre deuxième approche soit probablement la meilleure, mais examinons également notre troisième approche. Cela peut être utile lorsque nous ne pouvons pas tracer les données car elles ont trop de dimensions, ou lorsqu'il n'y a pas de concentration de données ou de séparation claire dans les groupes. Lorsque ces situations se produisent, il est recommandé d'essayer de réduire les dimensions des données avec une méthode appelée Analyse en composantes principales (ACP).

Remarque: La plupart des gens utilisent l'ACP pour réduire la dimensionnalité avant la visualisation. Il existe d'autres méthodes qui aident à la visualisation des données avant le clustering, telles que Regroupement spatial basé sur la densité d'applications avec bruit (DBSCAN) ainsi que Cartes auto-organisées (SOM) regroupement. Les deux sont des algorithmes de clustering, mais peuvent également être utilisés pour la visualisation de données. Étant donné que l'analyse de clustering n'a pas de norme d'or, il est important de comparer différentes visualisations et différents algorithmes.

PCA réduira les dimensions de nos données tout en essayant de conserver le plus d'informations possible. Commençons par avoir une idée du fonctionnement de l'ACP, puis nous pourrons choisir le nombre de dimensions de données auxquelles nous allons réduire nos données.

Pour chaque paire de caractéristiques, PCA voit si les valeurs supérieures d'une variable correspondent aux valeurs supérieures de l'autre variable, et il fait de même pour les valeurs inférieures. Ainsi, il calcule essentiellement dans quelle mesure les valeurs des caractéristiques varient les unes par rapport aux autres - nous appelons cela leur covariance. Ces résultats sont ensuite organisés dans une matrice, obtenant une matrice de covariance.

Après avoir obtenu la matrice de covariance, l'ACP essaie de trouver une combinaison linéaire de caractéristiques qui l'explique le mieux : elle ajuste les modèles linéaires jusqu'à ce qu'elle identifie celle qui explique la matrice de covariance. maximales montant de la variance.

Notes: L'ACP est une transformation linéaire et la linéarité est sensible à l'échelle des données. Par conséquent, l'ACP fonctionne mieux lorsque toutes les valeurs de données sont sur la même échelle. Cela peut être fait en soustrayant la colonne signifier à partir de ses valeurs et en divisant le résultat par son écart-type. Que l'on appelle normalisation des données. Avant d'utiliser PCA, assurez-vous que les données sont mises à l'échelle ! Si vous ne savez pas comment, lisez notre "Mise à l'échelle des données avec Scikit-Learn pour l'apprentissage automatique en Python"!

Avec la meilleure ligne (combinaison linéaire) trouvée, PCA obtient les directions de ses axes, appelées vecteurs propres, et ses coefficients linéaires, le valeurs propres. La combinaison des vecteurs propres et des valeurs propres – ou directions des axes et coefficients – est la Composants principaux de l'APC. Et c’est à ce moment-là que nous pouvons choisir notre nombre de dimensions en fonction de la variance expliquée de chaque caractéristique, en comprenant quels composants principaux nous voulons conserver ou éliminer en fonction du degré de variance qu’ils expliquent.

Après avoir obtenu les composants principaux, PCA utilise les vecteurs propres pour former un vecteur de caractéristiques qui réorientent les données des axes d'origine vers ceux représentés par les composants principaux - c'est ainsi que les dimensions des données sont réduites.

Remarque: Un détail important à prendre en considération ici est qu'en raison de sa nature linéaire, l'ACP concentrera l'essentiel de la variance expliquée dans les premières composantes principales. Ainsi, lorsque nous examinons la variance expliquée, nos deux premières composantes suffisent généralement. Mais cela peut être trompeur dans certains cas. Essayez donc de continuer à comparer différents tracés et algorithmes lors du regroupement pour voir s'ils contiennent des résultats similaires.

Avant d'appliquer l'ACP, nous devons choisir entre les Age colonne ou la Age Groups colonnes dans nos données précédemment encodées à chaud. Puisque les deux colonnes représentent la même information, l'introduire deux fois affecte notre variance de données. Si la Age Groups colonne est choisie, supprimez simplement la Age colonne utilisant les Pandas drop() méthode et réaffectez-la à la customer_data_oh variable:

customer_data_oh = customer_data_oh.drop(['Age'], axis=1)
customer_data_oh.shape 

Nos données comportent désormais 10 colonnes, ce qui signifie que nous pouvons obtenir une composante principale par colonne et choisir combien d'entre elles nous utiliserons en mesurant dans quelle mesure l'introduction d'une nouvelle dimension explique davantage la variance de nos données.

Faisons cela avec Scikit-Learn PCA. Nous allons calculer la variance expliquée de chaque dimension, donnée par explained_variance_ratio_ , puis regardez leur somme cumulée avec cumsum() :

from sklearn.decomposition import PCA

pca = PCA(n_components=10)
pca.fit_transform(customer_data_oh)
pca.explained_variance_ratio_.cumsum()

Nos variances expliquées cumulées sont :

array([0.509337  , 0.99909504, 0.99946364, 0.99965506, 0.99977937,
       0.99986848, 0.99993716, 1.        , 1.        , 1.        ])

Nous pouvons voir que la première dimension explique 50 % des données, et lorsqu'elles sont combinées à la deuxième dimension, elles expliquent 99 %. Cela signifie que les 2 premières dimensions expliquent déjà 99% de nos données. On peut donc appliquer une ACP à 2 composantes, obtenir nos composantes principales et les tracer :

from sklearn.decomposition import PCA

pca = PCA(n_components=2)
pcs = pca.fit_transform(customer_data_oh)

pc1_values = pcs[:,0]
pc2_values = pcs[:,1]
sns.scatterplot(x=pc1_values, y=pc2_values)

img

Le tracé des données après PCA est très similaire au tracé qui n'utilise que deux colonnes de données sans PCA. Notez que les points qui forment des groupes sont plus proches et un peu plus concentrés après l'ACP qu'avant.

img

Visualiser la structure hiérarchique avec des dendrogrammes

Jusqu'à présent, nous avons exploré les données, les colonnes catégorielles codées à chaud, décidé quelles colonnes étaient adaptées au clustering et réduit la dimensionnalité des données. Les graphiques indiquent que nous avons 5 clusters dans nos données, mais il existe également une autre façon de visualiser les relations entre nos points et d'aider à déterminer le nombre de clusters - en créant un dendrogramme (généralement mal orthographié comme dendogramme). dendro veux dire arbre en latin.

La dendrogramme est le résultat de la liaison de points dans un jeu de données. Il s'agit d'une représentation visuelle du processus de regroupement hiérarchique. Et comment fonctionne le processus de clustering hiérarchique ? Eh bien… ça dépend – probablement une réponse que vous avez déjà beaucoup entendue en science des données.

Comprendre le clustering hiérarchique

When the Algorithme de clustering hiérarchique (HCA) commence à relier les points et à trouver des clusters, il peut d'abord diviser les points en 2 grands groupes, puis diviser chacun de ces deux groupes en 2 groupes plus petits, ayant 4 groupes au total, qui est le diviser ainsi que top-down approche.

Alternativement, il peut faire le contraire - il peut regarder tous les points de données, trouver 2 points qui sont plus proches les uns des autres, les relier, puis trouver d'autres points qui sont les plus proches de ces points liés et continuer à construire les 2 groupes du de bas en haut. Qui est le agglomérant approche que nous développerons.

Étapes pour effectuer un clustering hiérarchique agglomératif

Pour rendre l'approche agglomérative encore plus claire, il y a des étapes de la Clustering Hiérarchique Agglomératif (AHC) algorithme:

  1. Au début, traitez chaque point de données comme un cluster. Par conséquent, le nombre de clusters au départ sera K - tandis que K est un nombre entier représentant le nombre de points de données.
  2. Formez un cluster en joignant les deux points de données les plus proches, ce qui donne des clusters K-1.
  3. Formez plus de grappes en joignant les deux grappes les plus proches, ce qui donne des grappes K-2.
  4. Répétez les trois étapes ci-dessus jusqu'à ce qu'un gros cluster soit formé.

Notes: Pour simplifier, nous disons "deux points de données les plus proches" aux étapes 2 et 3. Mais il existe d'autres façons de relier les points, comme nous le verrons dans un instant.

Si vous inversez les étapes de l’algorithme ACH, en passant de 4 à 1 – ce seraient les étapes pour *Clustering hiérarchique diviseur (DHC)*.

Notez que les HCA peuvent être soit source de division et descendante, soit agglomérante et ascendante. L'approche DHC descendante fonctionne mieux lorsque vous avez moins de clusters, mais plus grands, d'où une augmentation des coûts de calcul. D'autre part, l'approche AHC ascendante est adaptée lorsque vous avez de nombreux clusters plus petits. Il est informatiquement plus simple, plus utilisé et plus disponible.

Remarque: Que ce soit de haut en bas ou de bas en haut, la représentation du dendrogramme du processus de regroupement commencera toujours par une division en deux et se terminera avec chaque point individuel discriminé, une fois que sa structure sous-jacente est celle d'un arbre binaire.

Traçons notre dendrogramme de données client pour visualiser les relations hiérarchiques des données. Cette fois, nous utiliserons le scipy bibliothèque pour créer le dendrogramme pour notre ensemble de données :

import scipy.cluster.hierarchy as shc
import matplotlib.pyplot as plt

plt.figure(figsize=(10, 7))
plt.title("Customers Dendrogram")


selected_data = customer_data_oh.iloc[:, 1:3]
clusters = shc.linkage(selected_data, 
            method='ward', 
            metric="euclidean")
shc.dendrogram(Z=clusters)
plt.show()

La sortie du script ressemble à ceci :

img

Dans le script ci-dessus, nous avons généré les clusters et sous-clusters avec nos points, défini comment nos points seraient liés (en appliquant le ward méthode), et comment mesurer la distance entre les points (en utilisant la euclidean métrique).

Avec le tracé du dendrogramme, les processus décrits de DHC et AHC peuvent être visualisés. Pour visualiser l'approche descendante, commencez par le haut du dendrogramme et descendez, et faites l'inverse, en commençant par le bas et en vous déplaçant vers le haut pour visualiser l'approche ascendante.

Méthodes de liaison

Il existe de nombreuses autres méthodes de liaison, en comprenant mieux leur fonctionnement, vous serez en mesure de choisir celle qui convient à vos besoins. En plus de cela, chacun d'eux donnera des résultats différents lorsqu'il est appliqué. Il n'y a pas de règle fixe dans l'analyse de clustering, si possible, étudiez la nature du problème pour voir ce qui lui convient le mieux, testez différentes méthodes et inspectez les résultats.

Certaines des méthodes de liaison sont :

  • Attelage simple: également appelé Voisin le plus proche (NN). La distance entre les clusters est définie par la distance entre leurs membres les plus proches.

img

  • Liaison complète: également appelé Voisin le plus éloigné (FN), Algorithme du point le plus éloignéou Algorithme de Voor Hees. La distance entre les clusters est définie par la distance entre leurs membres les plus éloignés. Cette méthode est coûteuse en temps de calcul.

img

  • Liaison moyenne: aussi connu sous le nom UPGMA (Méthode de groupe de paires non pondérées avec moyenne arithmétique). Le pourcentage du nombre de points de chaque cluster est calculé par rapport au nombre de points des deux clusters s'ils étaient fusionnés.

img

  • Liaison pondérée: aussi connu sous le nom WPGMA (Méthode des groupes de paires pondérées avec moyenne arithmétique). Les points individuels des deux clusters contribuent à la distance agrégée entre un cluster plus petit et un cluster plus grand.
  • Liaison centroïde: également appelé UPGMC (Méthode de groupe de paires non pondérées utilisant des centroïdes). Un point défini par la moyenne de tous les points (centroïde) est calculé pour chaque cluster et la distance entre les clusters est la distance entre leurs centroïdes respectifs.

img

  • Lien de service: Aussi connu sous le nom MISSQ (Augmentation minimale de la somme des carrés). Il spécifie la distance entre deux clusters, calcule l'erreur de la somme des carrés (ESS) et choisit successivement les clusters suivants en fonction de l'ESS plus petit. La méthode de Ward cherche à minimiser l'augmentation de l'ESS à chaque étape. Par conséquent, minimiser les erreurs.

img

Mesures de distance

Outre le lien, nous pouvons également spécifier certaines des mesures de distance les plus utilisées :

  • Euclidienne: également appelé Pythagore ou ligne droite distance. Il calcule la distance entre deux points dans l'espace, en mesurant la longueur d'un segment de ligne qui passe entre eux. Il utilise le théorème de Pythagore et la valeur de distance est le résultat (c) de l'équation :

$$
c^2 = un^2 + b^2
$$

  • Manhattan: aussi appelé City-block, taxi distance. C'est la somme des différences absolues entre les mesures dans toutes les dimensions de deux points. Si ces dimensions sont de deux, cela revient à faire un virage à droite puis à gauche en marchant d'un pâté de maisons.

img

  • Minkowski: c'est une généralisation des distances euclidiennes et de Manhattan. C'est un moyen de calculer des distances basées sur les différences absolues à l'ordre de la métrique de Minkowski p. Bien qu'il soit défini pour tout p> 0, il est rarement utilisé pour des valeurs autres que 1, 2 et ∞ (infini). La distance de Minkowski est la même que la distance de Manhattan lorsque p = 1, et identique à la distance euclidienne lorsque p = 2.

$$
Dgauche(X,Ydroite) = gauche(sum_{i=1}^n |x_i-y_i|^pright)^{frac{1}{p}}
$$

img

  • Chebyshev: aussi connu sous le nom Échiquier distance. C'est le cas extrême de la distance de Minkowski. Lorsque nous utilisons l'infini comme valeur du paramètre p (p = ∞), nous nous retrouvons avec une métrique qui définit la distance comme la différence absolue maximale entre les coordonnées.
  • Cosinus: c'est la distance en cosinus angulaire entre deux séquences de points, ou vecteurs. La similitude cosinus est le produit scalaire des vecteurs divisé par le produit de leurs longueurs.
  • Jaccard: mesure la similarité entre des ensembles finis de points. Il est défini comme le nombre total de points (cardinalité) dans les points communs de chaque ensemble (intersection), divisé par le nombre total de points (cardinalité) du total des points des deux ensembles (union).
  • Jensen Shannon: basé sur la divergence de Kullback-Leibler. Il considère les distributions de probabilité des points et mesure la similarité entre ces distributions. C'est une méthode populaire de la théorie des probabilités et des statistiques.

Nous avons choisi quartier ainsi que Euclidienne pour le dendrogramme parce qu'il s'agit de la méthode et de la métrique les plus couramment utilisées. Ils donnent généralement de bons résultats puisque Ward relie les points en minimisant les erreurs, et Euclidien fonctionne bien dans les dimensions inférieures.

Dans cet exemple, nous travaillons avec deux caractéristiques (colonnes) des données marketing et 200 observations ou lignes. Comme le nombre d'observations est supérieur au nombre d'entités (200 > 2), nous travaillons dans un espace de faible dimension.

Lorsque le nombre de fonctionnalités (F) est plus grand que le nombre d'observations (N) - principalement écrit comme f >> N, cela signifie que nous avons un espace de grande dimension.

Si nous devions inclure plus d'attributs, nous avons donc plus de 200 entités, la distance euclidienne pourrait ne pas fonctionner très bien, car elle aurait du mal à mesurer toutes les petites distances dans un très grand espace qui ne fait que s'agrandir. En d'autres termes, l'approche de la distance euclidienne a des difficultés à travailler avec les données parcimonie. C'est un problème qui s'appelle la malédiction de la dimensionnalité. Les valeurs de distance deviendraient si petites, comme si elles devenaient "diluées" dans l'espace plus grand, déformées jusqu'à ce qu'elles deviennent 0.

Remarque: Si jamais vous rencontrez un ensemble de données avec f >> p, vous utiliserez probablement d'autres mesures de distance, telles que la Mahalanobis distance. Vous pouvez également réduire les dimensions du jeu de données en utilisant Analyse en composantes principales (ACP). Ce problème est fréquent notamment lors du regroupement de données de séquençage biologique.

Nous avons déjà discuté des paramètres, des liens et de la manière dont chacun d'entre eux peut avoir un impact sur nos résultats. Continuons maintenant l'analyse du dendrogramme et voyons comment cela peut nous donner une indication du nombre de clusters dans notre ensemble de données.

Trouver un nombre intéressant de grappes dans un dendrogramme revient à trouver le plus grand espace horizontal qui n'a pas de lignes verticales (l'espace avec les plus longues lignes verticales). Cela signifie qu'il y a plus de séparation entre les clusters.

Nous pouvons tracer une ligne horizontale qui passe par cette distance la plus longue :

plt.figure(figsize=(10, 7))
plt.title("Customers Dendogram with line")
clusters = shc.linkage(selected_data, 
            method='ward', 
            metric="euclidean")
shc.dendrogram(clusters)
plt.axhline(y = 125, color = 'r', linestyle = '-')

img

Après avoir localisé la ligne horizontale, nous comptons combien de fois nos lignes verticales ont été traversées par celle-ci - dans cet exemple, 5 fois. Donc 5 semble une bonne indication du nombre de clusters qui ont le plus de distance entre eux.

Notes: Le dendrogramme doit être considéré uniquement comme une référence lorsqu'il est utilisé pour choisir le nombre de grappes. Il peut facilement s'éloigner de ce nombre et est complètement influencé par le type de mesure de liaison et de distance. Lors de la réalisation d'une analyse approfondie des clusters, il est conseillé d'examiner les dendrogrammes avec différents liens et métriques et d'examiner les résultats générés avec les trois premières lignes dans lesquelles les clusters ont le plus de distance entre eux.

Implémentation d'un clustering hiérarchique agglomératif

Utilisation des données d'origine

Jusqu'à présent, nous avons calculé le nombre suggéré de clusters pour notre ensemble de données qui corrobore notre analyse initiale et notre analyse PCA. Nous pouvons maintenant créer notre modèle de clustering hiérarchique agglomératif à l'aide de Scikit-Learn AgglomerativeClustering et découvrez les labels des points marketing avec labels_:

from sklearn.cluster import AgglomerativeClustering

clustering_model = AgglomerativeClustering(n_clusters=5, affinity='euclidean', linkage='ward')
clustering_model.fit(selected_data)
clustering_model.labels_

Cela se traduit par:

array([4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3,
       4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 1,
       4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 2, 0, 2, 0, 2,
       1, 2, 0, 2, 0, 2, 0, 2, 0, 2, 1, 2, 0, 2, 1, 2, 0, 2, 0, 2, 0, 2,
       0, 2, 0, 2, 0, 2, 1, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2,
       0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2,
       0, 2])

Nous avons beaucoup étudié pour en arriver là. Et que signifient ces étiquettes ? Ici, nous avons chaque point de nos données étiqueté comme un groupe de 0 à 4 :

data_labels = clustering_model.labels_
sns.scatterplot(x='Annual Income (k$)', 
                y='Spending Score (1-100)', 
                data=selected_data, 
                hue=data_labels,
                pallete="rainbow").set_title('Labeled Customer Data')

img

Il s'agit de nos données clusterisées finales. Vous pouvez voir les points de données codés par couleur sous la forme de cinq clusters.

Les points de données en bas à droite (libellé : 0, points de données violets) appartiennent aux clients avec des salaires élevés mais de faibles dépenses. Ce sont les clients qui dépensent leur argent avec précaution.

De même, les clients en haut à droite (libellé : 2, points de données verts), sont les clients avec des salaires élevés et des dépenses élevées. C'est le type de clients que les entreprises ciblent.

Les clients au milieu (libellé : 1, points de données bleus) sont ceux qui ont un revenu moyen et des dépenses moyennes. Les plus grands nombres de clients appartiennent à cette catégorie. Les entreprises peuvent également cibler ces clients compte tenu du fait qu'ils sont très nombreux.

Les clients en bas à gauche (libellé : 4, rouge) sont les clients qui ont de faibles salaires et de faibles dépenses, ils pourraient être attirés par des promotions.

Et enfin, les clients en haut à gauche (libellé : 3, points de données orange) sont ceux qui ont des revenus élevés et de faibles dépenses, qui sont idéalement ciblés par le marketing.

Utilisation du résultat de l'ACP

Si nous étions dans un scénario différent, dans lequel nous devions réduire la dimensionnalité des données. Nous pourrions également facilement tracer les résultats de l'ACP clusterisée. Cela peut être fait en créant un autre modèle de clustering agglomératif et en obtenant une étiquette de données pour chaque composant principal :

clustering_model_pca = AgglomerativeClustering(n_clusters=5, affinity='euclidean', linkage='ward')
clustering_model_pca.fit(pcs)

data_labels_pca = clustering_model_pca.labels_

sns.scatterplot(x=pc1_values, 
                y=pc2_values,
                hue=data_labels_pca,
                palette="rainbow").set_title('Labeled Customer Data Reduced with PCA')

img

Remarquez que les deux résultats sont très similaires. La principale différence est que le premier résultat avec les données d'origine est beaucoup plus facile à expliquer. Il est clair que les clients peuvent être divisés en cinq groupes en fonction de leur revenu annuel et de leur score de dépenses. Alors que, dans l'approche PCA, nous prenons en considération toutes nos fonctionnalités, autant que nous pouvons regarder la variance expliquée par chacune d'elles, c'est un concept plus difficile à saisir, surtout lorsque l'on relève d'un service marketing.

Moins nous devons transformer nos données, mieux c'est.

Si vous disposez d'un ensemble de données très volumineux et complexe dans lequel vous devez effectuer une réduction de la dimensionnalité avant le regroupement, essayez d'analyser les relations linéaires entre chacune des caractéristiques et leurs résidus pour sauvegarder l'utilisation de l'ACP et améliorer l'explicabilité du processus. En créant un modèle linéaire par paire d'entités, vous pourrez comprendre comment les entités interagissent.

Si le volume de données est si important, il devient impossible de tracer les paires d'entités, de sélectionner un échantillon de vos données, aussi équilibré et proche de la distribution normale que possible et d'effectuer d'abord l'analyse sur l'échantillon, de le comprendre, d'affiner - et appliquez-le plus tard à l'ensemble de données.

Vous pouvez toujours choisir différentes techniques de visualisation de clustering selon la nature de vos données (linéaire, non linéaire) et les combiner ou les tester toutes si nécessaire.

Conclusion

La technique de clustering peut être très pratique lorsqu'il s'agit de données non étiquetées. Étant donné que la plupart des données dans le monde réel ne sont pas étiquetées et que l'annotation des données a des coûts plus élevés, des techniques de regroupement peuvent être utilisées pour étiqueter les données non étiquetées.

Dans ce guide, nous avons apporté un vrai problème de science des données, puisque les techniques de clustering sont largement utilisées dans l'analyse marketing (et aussi dans l'analyse biologique). Nous avons également expliqué de nombreuses étapes d'investigation pour arriver à un bon modèle de clustering hiérarchique et comment lire les dendrogrammes et demandé si l'ACP est une étape nécessaire. Notre objectif principal est que certains des pièges et différents scénarios dans lesquels nous pouvons trouver un clustering hiérarchique soient couverts.

Bon regroupement !

Horodatage:

Plus de Stackabuse