You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
639 lines
29 KiB
639 lines
29 KiB
{
|
|
"nbformat": 4,
|
|
"nbformat_minor": 0,
|
|
"metadata": {
|
|
"anaconda-cloud": "",
|
|
"kernelspec": {
|
|
"display_name": "R",
|
|
"language": "R",
|
|
"name": "ir"
|
|
},
|
|
"language_info": {
|
|
"codemirror_mode": "r",
|
|
"file_extension": ".r",
|
|
"mimetype": "text/x-r-source",
|
|
"name": "R",
|
|
"pygments_lexer": "r",
|
|
"version": "3.4.1"
|
|
},
|
|
"colab": {
|
|
"name": "lesson_14.ipynb",
|
|
"provenance": [],
|
|
"collapsed_sections": [],
|
|
"toc_visible": true
|
|
},
|
|
"coopTranslator": {
|
|
"original_hash": "ad65fb4aad0a156b42216e4929f490fc",
|
|
"translation_date": "2025-09-04T02:13:59+00:00",
|
|
"source_file": "5-Clustering/2-K-Means/solution/R/lesson_15-R.ipynb",
|
|
"language_code": "fr"
|
|
}
|
|
},
|
|
"cells": [
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "GULATlQXLXyR"
|
|
},
|
|
"source": [
|
|
"## Explorer le clustering K-Means avec R et les principes des données Tidy\n",
|
|
"\n",
|
|
"### [**Quiz avant le cours**](https://gray-sand-07a10f403.1.azurestaticapps.net/quiz/29/)\n",
|
|
"\n",
|
|
"Dans cette leçon, vous apprendrez à créer des clusters en utilisant le package Tidymodels et d'autres packages de l'écosystème R (que nous appellerons des amis 🧑🤝🧑), ainsi que le jeu de données sur la musique nigériane que vous avez importé précédemment. Nous couvrirons les bases du K-Means pour le clustering. Gardez à l'esprit que, comme vous l'avez appris dans la leçon précédente, il existe de nombreuses façons de travailler avec des clusters, et la méthode que vous utilisez dépend de vos données. Nous essayerons le K-Means car c'est la technique de clustering la plus courante. Allons-y !\n",
|
|
"\n",
|
|
"Termes que vous allez découvrir :\n",
|
|
"\n",
|
|
"- Scoring silhouette\n",
|
|
"\n",
|
|
"- Méthode du coude\n",
|
|
"\n",
|
|
"- Inertie\n",
|
|
"\n",
|
|
"- Variance\n",
|
|
"\n",
|
|
"### **Introduction**\n",
|
|
"\n",
|
|
"[Le clustering K-Means](https://wikipedia.org/wiki/K-means_clustering) est une méthode issue du domaine du traitement du signal. Elle est utilisée pour diviser et partitionner des groupes de données en `k clusters` en fonction des similarités de leurs caractéristiques.\n",
|
|
"\n",
|
|
"Les clusters peuvent être visualisés sous forme de [diagrammes de Voronoï](https://wikipedia.org/wiki/Voronoi_diagram), qui incluent un point (ou \"graine\") et sa région correspondante.\n",
|
|
"\n",
|
|
"<p >\n",
|
|
" <img src=\"../../images/voronoi.png\"\n",
|
|
" width=\"500\"/>\n",
|
|
" <figcaption>Infographie par Jen Looper</figcaption>\n",
|
|
"\n",
|
|
"Le clustering K-Means suit les étapes suivantes :\n",
|
|
"\n",
|
|
"1. Le data scientist commence par spécifier le nombre de clusters souhaités.\n",
|
|
"\n",
|
|
"2. Ensuite, l'algorithme sélectionne aléatoirement K observations du jeu de données pour servir de centres initiaux des clusters (c'est-à-dire des centroïdes).\n",
|
|
"\n",
|
|
"3. Chaque observation restante est ensuite assignée à son centroïde le plus proche.\n",
|
|
"\n",
|
|
"4. Les nouvelles moyennes de chaque cluster sont calculées, et le centroïde est déplacé vers cette moyenne.\n",
|
|
"\n",
|
|
"5. Maintenant que les centres ont été recalculés, chaque observation est à nouveau vérifiée pour voir si elle pourrait être plus proche d'un autre cluster. Tous les objets sont réassignés en utilisant les moyennes des clusters mises à jour. Les étapes d'assignation des clusters et de mise à jour des centroïdes sont répétées de manière itérative jusqu'à ce que les assignations de clusters cessent de changer (c'est-à-dire lorsque la convergence est atteinte). En général, l'algorithme s'arrête lorsque chaque nouvelle itération entraîne un déplacement négligeable des centroïdes et que les clusters deviennent statiques.\n",
|
|
"\n",
|
|
"<div>\n",
|
|
"\n",
|
|
"> Notez qu'en raison de la randomisation des k observations initiales utilisées comme centroïdes de départ, nous pouvons obtenir des résultats légèrement différents à chaque application de la procédure. Pour cette raison, la plupart des algorithmes utilisent plusieurs *démarrages aléatoires* et choisissent l'itération avec le WCSS le plus faible. Il est donc fortement recommandé d'exécuter K-Means avec plusieurs valeurs de *nstart* pour éviter un *optimum local indésirable.*\n",
|
|
"\n",
|
|
"</div>\n",
|
|
"\n",
|
|
"Cette courte animation utilisant les [illustrations](https://github.com/allisonhorst/stats-illustrations) d'Allison Horst explique le processus de clustering :\n",
|
|
"\n",
|
|
"<p >\n",
|
|
" <img src=\"../../images/kmeans.gif\"\n",
|
|
" width=\"550\"/>\n",
|
|
" <figcaption>Illustration par @allison_horst</figcaption>\n",
|
|
"\n",
|
|
"Une question fondamentale qui se pose dans le clustering est la suivante : comment savoir en combien de clusters diviser vos données ? Un inconvénient du K-Means est que vous devez définir `k`, c'est-à-dire le nombre de `centroïdes`. Heureusement, la `méthode du coude` aide à estimer une bonne valeur de départ pour `k`. Vous allez l'essayer dans un instant.\n",
|
|
"\n",
|
|
"### \n",
|
|
"\n",
|
|
"**Prérequis**\n",
|
|
"\n",
|
|
"Nous reprendrons là où nous nous sommes arrêtés dans la [leçon précédente](https://github.com/microsoft/ML-For-Beginners/blob/main/5-Clustering/1-Visualize/solution/R/lesson_14-R.ipynb), où nous avons analysé le jeu de données, réalisé de nombreuses visualisations et filtré le jeu de données pour des observations d'intérêt. Assurez-vous de la consulter !\n",
|
|
"\n",
|
|
"Nous aurons besoin de quelques packages pour compléter ce module. Vous pouvez les installer avec : `install.packages(c('tidyverse', 'tidymodels', 'cluster', 'summarytools', 'plotly', 'paletteer', 'factoextra', 'patchwork'))`\n",
|
|
"\n",
|
|
"Alternativement, le script ci-dessous vérifie si vous avez les packages nécessaires pour compléter ce module et les installe pour vous si certains manquent.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"metadata": {
|
|
"id": "ah_tBi58LXyi"
|
|
},
|
|
"source": [
|
|
"suppressWarnings(if(!require(\"pacman\")) install.packages(\"pacman\"))\n",
|
|
"\n",
|
|
"pacman::p_load('tidyverse', 'tidymodels', 'cluster', 'summarytools', 'plotly', 'paletteer', 'factoextra', 'patchwork')\n"
|
|
],
|
|
"execution_count": null,
|
|
"outputs": []
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "7e--UCUTLXym"
|
|
},
|
|
"source": [
|
|
"Allons-y !\n",
|
|
"\n",
|
|
"## 1. Une danse avec les données : Réduire aux 3 genres musicaux les plus populaires\n",
|
|
"\n",
|
|
"Voici un récapitulatif de ce que nous avons fait dans la leçon précédente. Décortiquons un peu les données !\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"metadata": {
|
|
"id": "Ycamx7GGLXyn"
|
|
},
|
|
"source": [
|
|
"# Load the core tidyverse and make it available in your current R session\n",
|
|
"library(tidyverse)\n",
|
|
"\n",
|
|
"# Import the data into a tibble\n",
|
|
"df <- read_csv(file = \"https://raw.githubusercontent.com/microsoft/ML-For-Beginners/main/5-Clustering/data/nigerian-songs.csv\", show_col_types = FALSE)\n",
|
|
"\n",
|
|
"# Narrow down to top 3 popular genres\n",
|
|
"nigerian_songs <- df %>% \n",
|
|
" # Concentrate on top 3 genres\n",
|
|
" filter(artist_top_genre %in% c(\"afro dancehall\", \"afropop\",\"nigerian pop\")) %>% \n",
|
|
" # Remove unclassified observations\n",
|
|
" filter(popularity != 0)\n",
|
|
"\n",
|
|
"\n",
|
|
"\n",
|
|
"# Visualize popular genres using bar plots\n",
|
|
"theme_set(theme_light())\n",
|
|
"nigerian_songs %>%\n",
|
|
" count(artist_top_genre) %>%\n",
|
|
" ggplot(mapping = aes(x = artist_top_genre, y = n,\n",
|
|
" fill = artist_top_genre)) +\n",
|
|
" geom_col(alpha = 0.8) +\n",
|
|
" paletteer::scale_fill_paletteer_d(\"ggsci::category10_d3\") +\n",
|
|
" ggtitle(\"Top genres\") +\n",
|
|
" theme(plot.title = element_text(hjust = 0.5))\n"
|
|
],
|
|
"execution_count": null,
|
|
"outputs": []
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "b5h5zmkPLXyp"
|
|
},
|
|
"source": [
|
|
"🤩 Ça s'est bien passé !\n",
|
|
"\n",
|
|
"## 2. Exploration supplémentaire des données.\n",
|
|
"\n",
|
|
"À quel point ces données sont-elles propres ? Vérifions la présence de valeurs aberrantes à l'aide de diagrammes en boîte. Nous allons nous concentrer sur les colonnes numériques avec moins de valeurs aberrantes (bien que vous puissiez nettoyer les valeurs aberrantes). Les diagrammes en boîte peuvent montrer l'étendue des données et aider à choisir les colonnes à utiliser. Notez que les diagrammes en boîte ne montrent pas la variance, un élément important pour des données bien adaptées au clustering. Veuillez consulter [cette discussion](https://stats.stackexchange.com/questions/91536/deduce-variance-from-boxplot) pour en savoir plus.\n",
|
|
"\n",
|
|
"Les [diagrammes en boîte](https://en.wikipedia.org/wiki/Box_plot) sont utilisés pour représenter graphiquement la distribution des données `numériques`, alors commençons par *sélectionner* toutes les colonnes numériques ainsi que les genres musicaux populaires.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"metadata": {
|
|
"id": "HhNreJKLLXyq"
|
|
},
|
|
"source": [
|
|
"# Select top genre column and all other numeric columns\n",
|
|
"df_numeric <- nigerian_songs %>% \n",
|
|
" select(artist_top_genre, where(is.numeric)) \n",
|
|
"\n",
|
|
"# Display the data\n",
|
|
"df_numeric %>% \n",
|
|
" slice_head(n = 5)\n"
|
|
],
|
|
"execution_count": null,
|
|
"outputs": []
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "uYXrwJRaLXyq"
|
|
},
|
|
"source": [
|
|
"Voyez comme l'assistant de sélection `where` rend cela facile 💁 ? Découvrez d'autres fonctions similaires [ici](https://tidyselect.r-lib.org/).\n",
|
|
"\n",
|
|
"Puisque nous allons créer un boxplot pour chaque caractéristique numérique et que nous voulons éviter d'utiliser des boucles, reformons nos données dans un format *plus long* qui nous permettra de tirer parti des `facets` - des sous-graphiques affichant chacun un sous-ensemble des données.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"metadata": {
|
|
"id": "gd5bR3f8LXys"
|
|
},
|
|
"source": [
|
|
"# Pivot data from wide to long\n",
|
|
"df_numeric_long <- df_numeric %>% \n",
|
|
" pivot_longer(!artist_top_genre, names_to = \"feature_names\", values_to = \"values\") \n",
|
|
"\n",
|
|
"# Print out data\n",
|
|
"df_numeric_long %>% \n",
|
|
" slice_head(n = 15)\n"
|
|
],
|
|
"execution_count": null,
|
|
"outputs": []
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "-7tE1swnLXyv"
|
|
},
|
|
"source": [
|
|
"Beaucoup plus long ! Maintenant, il est temps de passer à quelques `ggplots` ! Alors, quel `geom` allons-nous utiliser ?\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"metadata": {
|
|
"id": "r88bIsyuLXyy"
|
|
},
|
|
"source": [
|
|
"# Make a box plot\n",
|
|
"df_numeric_long %>% \n",
|
|
" ggplot(mapping = aes(x = feature_names, y = values, fill = feature_names)) +\n",
|
|
" geom_boxplot() +\n",
|
|
" facet_wrap(~ feature_names, ncol = 4, scales = \"free\") +\n",
|
|
" theme(legend.position = \"none\")\n"
|
|
],
|
|
"execution_count": null,
|
|
"outputs": []
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "EYVyKIUELXyz"
|
|
},
|
|
"source": [
|
|
"Facile-gg !\n",
|
|
"\n",
|
|
"Nous pouvons maintenant constater que ces données sont un peu bruyantes : en observant chaque colonne sous forme de boîte à moustaches, on peut repérer des valeurs aberrantes. Vous pourriez parcourir l'ensemble de données et supprimer ces valeurs aberrantes, mais cela rendrait les données assez limitées.\n",
|
|
"\n",
|
|
"Pour l'instant, choisissons les colonnes que nous utiliserons pour notre exercice de regroupement. Prenons les colonnes numériques ayant des plages similaires. Nous pourrions encoder `artist_top_genre` en numérique, mais nous allons l'ignorer pour le moment.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"metadata": {
|
|
"id": "-wkpINyZLXy0"
|
|
},
|
|
"source": [
|
|
"# Select variables with similar ranges\n",
|
|
"df_numeric_select <- df_numeric %>% \n",
|
|
" select(popularity, danceability, acousticness, loudness, energy) \n",
|
|
"\n",
|
|
"# Normalize data\n",
|
|
"# df_numeric_select <- scale(df_numeric_select)\n"
|
|
],
|
|
"execution_count": null,
|
|
"outputs": []
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "D7dLzgpqLXy1"
|
|
},
|
|
"source": [
|
|
"## 3. Calcul des clusters k-means dans R\n",
|
|
"\n",
|
|
"Nous pouvons calculer les k-means dans R avec la fonction intégrée `kmeans`, voir `help(\"kmeans()\")`. La fonction `kmeans()` accepte un tableau de données avec toutes les colonnes numériques comme argument principal.\n",
|
|
"\n",
|
|
"La première étape lors de l'utilisation du clustering k-means est de spécifier le nombre de clusters (k) qui seront générés dans la solution finale. Nous savons qu'il y a 3 genres musicaux que nous avons extraits du jeu de données, alors essayons avec 3 :\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"metadata": {
|
|
"id": "uC4EQ5w7LXy5"
|
|
},
|
|
"source": [
|
|
"set.seed(2056)\n",
|
|
"# Kmeans clustering for 3 clusters\n",
|
|
"kclust <- kmeans(\n",
|
|
" df_numeric_select,\n",
|
|
" # Specify the number of clusters\n",
|
|
" centers = 3,\n",
|
|
" # How many random initial configurations\n",
|
|
" nstart = 25\n",
|
|
")\n",
|
|
"\n",
|
|
"# Display clustering object\n",
|
|
"kclust\n"
|
|
],
|
|
"execution_count": null,
|
|
"outputs": []
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "hzfhscWrLXy-"
|
|
},
|
|
"source": [
|
|
"L'objet kmeans contient plusieurs informations bien expliquées dans `help(\"kmeans()\")`. Pour l'instant, concentrons-nous sur quelques-unes. Nous voyons que les données ont été regroupées en 3 clusters de tailles 65, 110, 111. La sortie contient également les centres des clusters (moyennes) pour les 3 groupes sur les 5 variables.\n",
|
|
"\n",
|
|
"Le vecteur de clustering correspond à l'affectation de cluster pour chaque observation. Utilisons la fonction `augment` pour ajouter l'affectation de cluster au jeu de données original.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"metadata": {
|
|
"id": "0XwwpFGQLXy_"
|
|
},
|
|
"source": [
|
|
"# Add predicted cluster assignment to data set\n",
|
|
"augment(kclust, df_numeric_select) %>% \n",
|
|
" relocate(.cluster) %>% \n",
|
|
" slice_head(n = 10)\n"
|
|
],
|
|
"execution_count": null,
|
|
"outputs": []
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "NXIVXXACLXzA"
|
|
},
|
|
"source": [
|
|
"Parfait, nous venons de diviser notre ensemble de données en 3 groupes. Alors, à quel point notre regroupement est-il bon 🤷 ? Jetons un coup d'œil au `Silhouette score`.\n",
|
|
"\n",
|
|
"### **Score de silhouette**\n",
|
|
"\n",
|
|
"[L'analyse de silhouette](https://en.wikipedia.org/wiki/Silhouette_(clustering)) peut être utilisée pour étudier la distance de séparation entre les clusters obtenus. Ce score varie de -1 à 1, et si le score est proche de 1, cela signifie que le cluster est dense et bien séparé des autres clusters. Une valeur proche de 0 représente des clusters qui se chevauchent, avec des échantillons très proches de la frontière de décision des clusters voisins. [source](https://dzone.com/articles/kmeans-silhouette-score-explained-with-python-exam).\n",
|
|
"\n",
|
|
"La méthode de silhouette moyenne calcule la silhouette moyenne des observations pour différentes valeurs de *k*. Un score moyen de silhouette élevé indique un bon regroupement.\n",
|
|
"\n",
|
|
"La fonction `silhouette` du package cluster permet de calculer la largeur moyenne de silhouette.\n",
|
|
"\n",
|
|
"> La silhouette peut être calculée avec n'importe quelle [distance](https://en.wikipedia.org/wiki/Distance \"Distance\"), comme la [distance euclidienne](https://en.wikipedia.org/wiki/Euclidean_distance \"Euclidean distance\") ou la [distance de Manhattan](https://en.wikipedia.org/wiki/Manhattan_distance \"Manhattan distance\") que nous avons abordées dans la [leçon précédente](https://github.com/microsoft/ML-For-Beginners/blob/main/5-Clustering/1-Visualize/solution/R/lesson_14-R.ipynb).\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"metadata": {
|
|
"id": "Jn0McL28LXzB"
|
|
},
|
|
"source": [
|
|
"# Load cluster package\n",
|
|
"library(cluster)\n",
|
|
"\n",
|
|
"# Compute average silhouette score\n",
|
|
"ss <- silhouette(kclust$cluster,\n",
|
|
" # Compute euclidean distance\n",
|
|
" dist = dist(df_numeric_select))\n",
|
|
"mean(ss[, 3])\n"
|
|
],
|
|
"execution_count": null,
|
|
"outputs": []
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "QyQRn97nLXzC"
|
|
},
|
|
"source": [
|
|
"Notre score est **0,549**, ce qui le place en plein milieu. Cela indique que nos données ne sont pas particulièrement adaptées à ce type de regroupement. Voyons si nous pouvons confirmer cette intuition visuellement. Le [package factoextra](https://rpkgs.datanovia.com/factoextra/index.html) fournit des fonctions (`fviz_cluster()`) pour visualiser les regroupements.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"metadata": {
|
|
"id": "7a6Km1_FLXzD"
|
|
},
|
|
"source": [
|
|
"library(factoextra)\n",
|
|
"\n",
|
|
"# Visualize clustering results\n",
|
|
"fviz_cluster(kclust, df_numeric_select)\n"
|
|
],
|
|
"execution_count": null,
|
|
"outputs": []
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "IBwCWt-0LXzD"
|
|
},
|
|
"source": [
|
|
"Le chevauchement des clusters indique que nos données ne sont pas particulièrement adaptées à ce type de regroupement, mais poursuivons tout de même.\n",
|
|
"\n",
|
|
"## 4. Déterminer le nombre optimal de clusters\n",
|
|
"\n",
|
|
"Une question fondamentale qui se pose souvent dans le cadre du clustering K-Means est la suivante : sans étiquettes de classe connues, comment savoir en combien de clusters diviser vos données ?\n",
|
|
"\n",
|
|
"Une méthode pour tenter de le déterminer consiste à utiliser un échantillon de données pour `créer une série de modèles de clustering` avec un nombre croissant de clusters (par exemple de 1 à 10), et à évaluer des métriques de clustering telles que le **score de Silhouette.**\n",
|
|
"\n",
|
|
"Déterminons le nombre optimal de clusters en appliquant l'algorithme de clustering pour différentes valeurs de *k* et en évaluant la **somme des carrés intra-cluster** (WCSS). La somme totale des carrés intra-cluster (WCSS) mesure la compacité du regroupement, et nous souhaitons qu'elle soit aussi faible que possible, des valeurs plus basses signifiant que les points de données sont plus proches les uns des autres.\n",
|
|
"\n",
|
|
"Explorons l'effet de différents choix de `k`, de 1 à 10, sur ce regroupement.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"metadata": {
|
|
"id": "hSeIiylDLXzE"
|
|
},
|
|
"source": [
|
|
"# Create a series of clustering models\n",
|
|
"kclusts <- tibble(k = 1:10) %>% \n",
|
|
" # Perform kmeans clustering for 1,2,3 ... ,10 clusters\n",
|
|
" mutate(model = map(k, ~ kmeans(df_numeric_select, centers = .x, nstart = 25)),\n",
|
|
" # Farm out clustering metrics eg WCSS\n",
|
|
" glanced = map(model, ~ glance(.x))) %>% \n",
|
|
" unnest(cols = glanced)\n",
|
|
" \n",
|
|
"\n",
|
|
"# View clustering rsulsts\n",
|
|
"kclusts\n"
|
|
],
|
|
"execution_count": null,
|
|
"outputs": []
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "m7rS2U1eLXzE"
|
|
},
|
|
"source": [
|
|
"Maintenant que nous avons la somme totale des carrés intra-clusters (tot.withinss) pour chaque algorithme de regroupement avec un centre *k*, nous utilisons la [méthode du coude](https://fr.wikipedia.org/wiki/M%C3%A9thode_du_coude_(regroupement)) pour déterminer le nombre optimal de clusters. Cette méthode consiste à tracer la WCSS en fonction du nombre de clusters, puis à choisir le [coude de la courbe](https://fr.wikipedia.org/wiki/Coude_de_la_courbe \"Coude de la courbe\") comme le nombre de clusters à utiliser.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"metadata": {
|
|
"id": "o_DjHGItLXzF"
|
|
},
|
|
"source": [
|
|
"set.seed(2056)\n",
|
|
"# Use elbow method to determine optimum number of clusters\n",
|
|
"kclusts %>% \n",
|
|
" ggplot(mapping = aes(x = k, y = tot.withinss)) +\n",
|
|
" geom_line(size = 1.2, alpha = 0.8, color = \"#FF7F0EFF\") +\n",
|
|
" geom_point(size = 2, color = \"#FF7F0EFF\")\n"
|
|
],
|
|
"execution_count": null,
|
|
"outputs": []
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "pLYyt5XSLXzG"
|
|
},
|
|
"source": [
|
|
"Le graphique montre une grande réduction de WCSS (donc une *compacité* accrue) lorsque le nombre de clusters passe de un à deux, et une réduction encore notable de deux à trois clusters. Après cela, la réduction est moins marquée, ce qui crée un `coude` 💪 dans le graphique autour de trois clusters. Cela indique clairement qu'il y a deux à trois groupes de points de données raisonnablement bien séparés.\n",
|
|
"\n",
|
|
"Nous pouvons maintenant procéder à l'extraction du modèle de clustering où `k = 3` :\n",
|
|
"\n",
|
|
"> `pull()`: utilisé pour extraire une seule colonne\n",
|
|
">\n",
|
|
"> `pluck()`: utilisé pour indexer des structures de données telles que des listes\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"metadata": {
|
|
"id": "JP_JPKBILXzG"
|
|
},
|
|
"source": [
|
|
"# Extract k = 3 clustering\n",
|
|
"final_kmeans <- kclusts %>% \n",
|
|
" filter(k == 3) %>% \n",
|
|
" pull(model) %>% \n",
|
|
" pluck(1)\n",
|
|
"\n",
|
|
"\n",
|
|
"final_kmeans\n"
|
|
],
|
|
"execution_count": null,
|
|
"outputs": []
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "l_PDTu8tLXzI"
|
|
},
|
|
"source": [
|
|
"Super ! Visualisons les clusters obtenus. Envie d'un peu d'interactivité avec `plotly` ?\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"metadata": {
|
|
"id": "dNcleFe-LXzJ"
|
|
},
|
|
"source": [
|
|
"# Add predicted cluster assignment to data set\n",
|
|
"results <- augment(final_kmeans, df_numeric_select) %>% \n",
|
|
" bind_cols(df_numeric %>% select(artist_top_genre)) \n",
|
|
"\n",
|
|
"# Plot cluster assignments\n",
|
|
"clust_plt <- results %>% \n",
|
|
" ggplot(mapping = aes(x = popularity, y = danceability, color = .cluster, shape = artist_top_genre)) +\n",
|
|
" geom_point(size = 2, alpha = 0.8) +\n",
|
|
" paletteer::scale_color_paletteer_d(\"ggthemes::Tableau_10\")\n",
|
|
"\n",
|
|
"ggplotly(clust_plt)\n"
|
|
],
|
|
"execution_count": null,
|
|
"outputs": []
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "6JUM_51VLXzK"
|
|
},
|
|
"source": [
|
|
"Peut-être aurions-nous pu nous attendre à ce que chaque cluster (représenté par des couleurs différentes) ait des genres distincts (représentés par des formes différentes).\n",
|
|
"\n",
|
|
"Examinons la précision du modèle.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"metadata": {
|
|
"id": "HdIMUGq7LXzL"
|
|
},
|
|
"source": [
|
|
"# Assign genres to predefined integers\n",
|
|
"label_count <- results %>% \n",
|
|
" group_by(artist_top_genre) %>% \n",
|
|
" mutate(id = cur_group_id()) %>% \n",
|
|
" ungroup() %>% \n",
|
|
" summarise(correct_labels = sum(.cluster == id))\n",
|
|
"\n",
|
|
"\n",
|
|
"# Print results \n",
|
|
"cat(\"Result:\", label_count$correct_labels, \"out of\", nrow(results), \"samples were correctly labeled.\")\n",
|
|
"\n",
|
|
"cat(\"\\nAccuracy score:\", label_count$correct_labels/nrow(results))\n"
|
|
],
|
|
"execution_count": null,
|
|
"outputs": []
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "C50wvaAOLXzM"
|
|
},
|
|
"source": [
|
|
"La précision de ce modèle n'est pas mauvaise, mais elle n'est pas excellente non plus. Il se peut que les données ne se prêtent pas bien au clustering par K-Means. Ces données sont trop déséquilibrées, trop peu corrélées et il y a trop de variance entre les valeurs des colonnes pour permettre un bon regroupement. En fait, les clusters qui se forment sont probablement fortement influencés ou biaisés par les trois catégories de genres que nous avons définies plus haut.\n",
|
|
"\n",
|
|
"Néanmoins, ce fut un processus d'apprentissage très enrichissant !\n",
|
|
"\n",
|
|
"Dans la documentation de Scikit-learn, vous pouvez voir qu'un modèle comme celui-ci, avec des clusters peu bien délimités, présente un problème de \"variance\" :\n",
|
|
"\n",
|
|
"<p >\n",
|
|
" <img src=\"../../images/problems.png\"\n",
|
|
" width=\"500\"/>\n",
|
|
" <figcaption>Infographie tirée de Scikit-learn</figcaption>\n",
|
|
"\n",
|
|
"\n",
|
|
"\n",
|
|
"## **Variance**\n",
|
|
"\n",
|
|
"La variance est définie comme \"la moyenne des carrés des écarts par rapport à la moyenne\" [source](https://www.mathsisfun.com/data/standard-deviation.html). Dans le contexte de ce problème de clustering, cela fait référence au fait que les chiffres de notre jeu de données ont tendance à s'écarter un peu trop de la moyenne.\n",
|
|
"\n",
|
|
"✅ C'est un excellent moment pour réfléchir à toutes les façons dont vous pourriez corriger ce problème. Ajuster un peu plus les données ? Utiliser d'autres colonnes ? Employer un algorithme différent ? Indice : Essayez de [normaliser vos données](https://www.mygreatlearning.com/blog/learning-data-science-with-k-means-clustering/) pour les mettre à l'échelle et testez d'autres colonnes.\n",
|
|
"\n",
|
|
"> Essayez ce '[calculateur de variance](https://www.calculatorsoup.com/calculators/statistics/variance-calculator.php)' pour mieux comprendre le concept.\n",
|
|
"\n",
|
|
"------------------------------------------------------------------------\n",
|
|
"\n",
|
|
"## **🚀Défi**\n",
|
|
"\n",
|
|
"Passez un peu de temps avec ce notebook en ajustant les paramètres. Pouvez-vous améliorer la précision du modèle en nettoyant davantage les données (en supprimant les valeurs aberrantes, par exemple) ? Vous pouvez utiliser des pondérations pour donner plus d'importance à certains échantillons de données. Que pouvez-vous faire d'autre pour créer de meilleurs clusters ?\n",
|
|
"\n",
|
|
"Indice : Essayez de mettre vos données à l'échelle. Il y a du code commenté dans le notebook qui ajoute une mise à l'échelle standard pour que les colonnes de données se ressemblent davantage en termes de plage. Vous constaterez que, bien que le score de silhouette diminue, le \"coude\" dans le graphique du coude devient plus lisse. Cela s'explique par le fait que laisser les données non mises à l'échelle permet aux données avec moins de variance d'avoir plus de poids. Lisez un peu plus sur ce problème [ici](https://stats.stackexchange.com/questions/21222/are-mean-normalization-and-feature-scaling-needed-for-k-means-clustering/21226#21226).\n",
|
|
"\n",
|
|
"## [**Quiz post-cours**](https://gray-sand-07a10f403.1.azurestaticapps.net/quiz/30/)\n",
|
|
"\n",
|
|
"## **Révision et auto-apprentissage**\n",
|
|
"\n",
|
|
"- Jetez un œil à un simulateur de K-Means [comme celui-ci](https://user.ceng.metu.edu.tr/~akifakkus/courses/ceng574/k-means/). Vous pouvez utiliser cet outil pour visualiser des points de données d'exemple et déterminer leurs centroïdes. Vous pouvez modifier l'aléatoire des données, le nombre de clusters et le nombre de centroïdes. Cela vous aide-t-il à mieux comprendre comment les données peuvent être regroupées ?\n",
|
|
"\n",
|
|
"- Consultez également [ce document sur K-Means](https://stanford.edu/~cpiech/cs221/handouts/kmeans.html) de Stanford.\n",
|
|
"\n",
|
|
"Envie de tester vos nouvelles compétences en clustering sur des ensembles de données qui se prêtent bien au clustering par K-Means ? Consultez :\n",
|
|
"\n",
|
|
"- [Entraîner et évaluer des modèles de clustering](https://rpubs.com/eR_ic/clustering) en utilisant Tidymodels et ses outils associés\n",
|
|
"\n",
|
|
"- [Analyse de clusters K-Means](https://uc-r.github.io/kmeans_clustering), Guide de programmation R pour l'analyse commerciale de l'UC\n",
|
|
"\n",
|
|
"- [Clustering K-Means avec les principes des données tidy](https://www.tidymodels.org/learn/statistics/k-means/)\n",
|
|
"\n",
|
|
"## **Devoir**\n",
|
|
"\n",
|
|
"[Essayez différentes méthodes de clustering](https://github.com/microsoft/ML-For-Beginners/blob/main/5-Clustering/2-K-Means/assignment.md)\n",
|
|
"\n",
|
|
"## REMERCIEMENTS À :\n",
|
|
"\n",
|
|
"[Jen Looper](https://www.twitter.com/jenlooper) pour avoir créé la version Python originale de ce module ♥️\n",
|
|
"\n",
|
|
"[`Allison Horst`](https://twitter.com/allison_horst/) pour ses illustrations incroyables qui rendent R plus accueillant et engageant. Retrouvez plus d'illustrations dans sa [galerie](https://www.google.com/url?q=https://github.com/allisonhorst/stats-illustrations&sa=D&source=editors&ust=1626380772530000&usg=AOvVaw3zcfyCizFQZpkSLzxiiQEM).\n",
|
|
"\n",
|
|
"Bon apprentissage,\n",
|
|
"\n",
|
|
"[Eric](https://twitter.com/ericntay), Gold Microsoft Learn Student Ambassador.\n",
|
|
"\n",
|
|
"<p >\n",
|
|
" <img src=\"../../images/r_learners_sm.jpeg\"\n",
|
|
" width=\"500\"/>\n",
|
|
" <figcaption>Illustration par @allison_horst</figcaption>\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"\n---\n\n**Avertissement** : \nCe document a été traduit à l'aide du service de traduction automatique [Co-op Translator](https://github.com/Azure/co-op-translator). Bien que nous nous efforcions d'assurer l'exactitude, veuillez noter que les traductions automatisées peuvent contenir des erreurs ou des inexactitudes. Le document original dans sa langue d'origine doit être considéré comme la source faisant autorité. Pour des informations critiques, il est recommandé de faire appel à une traduction humaine professionnelle. Nous déclinons toute responsabilité en cas de malentendus ou d'interprétations erronées résultant de l'utilisation de cette traduction.\n"
|
|
]
|
|
}
|
|
]
|
|
} |