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.
642 lines
28 KiB
642 lines
28 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-06T12:19:15+00:00",
|
|
"source_file": "5-Clustering/2-K-Means/solution/R/lesson_15-R.ipynb",
|
|
"language_code": "nl"
|
|
}
|
|
},
|
|
"cells": [
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "GULATlQXLXyR"
|
|
},
|
|
"source": [
|
|
"## Verken K-Means clustering met R en de principes van Tidy data.\n",
|
|
"\n",
|
|
"### [**Pre-lecture quiz**](https://gray-sand-07a10f403.1.azurestaticapps.net/quiz/29/)\n",
|
|
"\n",
|
|
"In deze les leer je hoe je clusters kunt maken met behulp van het Tidymodels-pakket en andere pakketten in het R-ecosysteem (we noemen ze vrienden 🧑🤝🧑), en de Nigeriaanse muziekdataset die je eerder hebt geïmporteerd. We behandelen de basis van K-Means voor clustering. Onthoud dat, zoals je in de vorige les hebt geleerd, er veel manieren zijn om met clusters te werken en dat de methode die je gebruikt afhangt van je data. We proberen K-Means omdat dit de meest gebruikelijke clusteringtechniek is. Laten we beginnen!\n",
|
|
"\n",
|
|
"Begrippen die je zult leren:\n",
|
|
"\n",
|
|
"- Silhouettescore\n",
|
|
"\n",
|
|
"- Elbow-methode\n",
|
|
"\n",
|
|
"- Inertie\n",
|
|
"\n",
|
|
"- Variantie\n",
|
|
"\n",
|
|
"### **Introductie**\n",
|
|
"\n",
|
|
"[K-Means Clustering](https://wikipedia.org/wiki/K-means_clustering) is een methode afkomstig uit het domein van signaalverwerking. Het wordt gebruikt om groepen data te verdelen en te groeperen in `k clusters` op basis van overeenkomsten in hun kenmerken.\n",
|
|
"\n",
|
|
"De clusters kunnen worden gevisualiseerd als [Voronoi-diagrammen](https://wikipedia.org/wiki/Voronoi_diagram), die een punt (of 'zaad') en het bijbehorende gebied bevatten.\n",
|
|
"\n",
|
|
"<p >\n",
|
|
" <img src=\"../../images/voronoi.png\"\n",
|
|
" width=\"500\"/>\n",
|
|
" <figcaption>Infographic door Jen Looper</figcaption>\n",
|
|
"\n",
|
|
"\n",
|
|
"K-Means clustering omvat de volgende stappen:\n",
|
|
"\n",
|
|
"1. De datawetenschapper begint met het specificeren van het gewenste aantal clusters dat moet worden gemaakt.\n",
|
|
"\n",
|
|
"2. Vervolgens selecteert het algoritme willekeurig K observaties uit de dataset om te dienen als de initiële centra voor de clusters (d.w.z. centroids).\n",
|
|
"\n",
|
|
"3. Daarna wordt elke resterende observatie toegewezen aan het dichtstbijzijnde centroid.\n",
|
|
"\n",
|
|
"4. Vervolgens worden de nieuwe gemiddelden van elk cluster berekend en wordt het centroid verplaatst naar het gemiddelde.\n",
|
|
"\n",
|
|
"5. Nu de centra opnieuw zijn berekend, wordt elke observatie opnieuw gecontroleerd om te zien of deze dichter bij een ander cluster zou kunnen liggen. Alle objecten worden opnieuw toegewezen met behulp van de bijgewerkte cluster-gemiddelden. De stappen van cluster-toewijzing en centroid-update worden iteratief herhaald totdat de cluster-toewijzingen niet meer veranderen (d.w.z. wanneer convergentie is bereikt). Meestal stopt het algoritme wanneer elke nieuwe iteratie resulteert in een verwaarloosbare verplaatsing van de centroids en de clusters statisch worden.\n",
|
|
"\n",
|
|
"<div>\n",
|
|
"\n",
|
|
"> Houd er rekening mee dat door de randomisatie van de initiële k observaties die als startcentroids worden gebruikt, we elke keer dat we de procedure toepassen iets andere resultaten kunnen krijgen. Om deze reden gebruiken de meeste algoritmen meerdere *willekeurige starts* en kiezen ze de iteratie met de laagste WCSS. Het wordt daarom sterk aanbevolen om K-Means altijd met meerdere waarden van *nstart* uit te voeren om een *ongewenst lokaal optimum* te vermijden.\n",
|
|
"\n",
|
|
"</div>\n",
|
|
"\n",
|
|
"Deze korte animatie met het [kunstwerk](https://github.com/allisonhorst/stats-illustrations) van Allison Horst legt het clusteringproces uit:\n",
|
|
"\n",
|
|
"<p >\n",
|
|
" <img src=\"../../images/kmeans.gif\"\n",
|
|
" width=\"550\"/>\n",
|
|
" <figcaption>Kunstwerk door @allison_horst</figcaption>\n",
|
|
"\n",
|
|
"\n",
|
|
"\n",
|
|
"Een fundamentele vraag die bij clustering opkomt, is deze: hoe weet je in hoeveel clusters je je data moet verdelen? Een nadeel van het gebruik van K-Means is dat je `k` moet vaststellen, dat wil zeggen het aantal `centroids`. Gelukkig helpt de `elbow-methode` om een goede startwaarde voor `k` te schatten. Je gaat dit zo meteen proberen.\n",
|
|
"\n",
|
|
"### \n",
|
|
"\n",
|
|
"**Vereisten**\n",
|
|
"\n",
|
|
"We gaan verder waar we in de [vorige les](https://github.com/microsoft/ML-For-Beginners/blob/main/5-Clustering/1-Visualize/solution/R/lesson_14-R.ipynb) zijn gestopt, waar we de dataset analyseerden, veel visualisaties maakten en de dataset filterden op interessante observaties. Zorg ervoor dat je die les bekijkt!\n",
|
|
"\n",
|
|
"We hebben een aantal pakketten nodig om deze module te voltooien. Je kunt ze installeren met: `install.packages(c('tidyverse', 'tidymodels', 'cluster', 'summarytools', 'plotly', 'paletteer', 'factoextra', 'patchwork'))`\n",
|
|
"\n",
|
|
"Als alternatief controleert het onderstaande script of je de benodigde pakketten hebt om deze module te voltooien en installeert ze voor je als er enkele ontbreken.\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": [
|
|
"Laten we meteen aan de slag gaan!\n",
|
|
"\n",
|
|
"## 1. Een dans met data: Beperk je tot de 3 populairste muziekgenres\n",
|
|
"\n",
|
|
"Dit is een samenvatting van wat we in de vorige les hebben gedaan. Laten we wat data analyseren!\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": [
|
|
"🤩 Dat ging goed!\n",
|
|
"\n",
|
|
"## 2. Meer data verkennen.\n",
|
|
"\n",
|
|
"Hoe schoon is deze data? Laten we controleren op uitschieters met behulp van boxplots. We richten ons op numerieke kolommen met minder uitschieters (hoewel je de uitschieters zou kunnen verwijderen). Boxplots kunnen de spreiding van de data laten zien en helpen bij het kiezen van welke kolommen te gebruiken. Let op, boxplots tonen geen variatie, een belangrijk element van goed clusterbare data. Zie [deze discussie](https://stats.stackexchange.com/questions/91536/deduce-variance-from-boxplot) voor meer informatie.\n",
|
|
"\n",
|
|
"[Boxplots](https://en.wikipedia.org/wiki/Box_plot) worden gebruikt om de verdeling van `numerieke` data grafisch weer te geven, dus laten we beginnen met het *selecteren* van alle numerieke kolommen samen met de populaire muziekgenres.\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": [
|
|
"Zie hoe de selectiehelper `where` dit eenvoudig maakt 💁? Ontdek hier [andere functies](https://tidyselect.r-lib.org/).\n",
|
|
"\n",
|
|
"Omdat we een boxplot willen maken voor elke numerieke eigenschap en het gebruik van loops willen vermijden, gaan we onze data herformatteren naar een *langere* indeling. Hiermee kunnen we gebruik maken van `facets` - deelplots die elk een subset van de data weergeven.\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": [
|
|
"Veel langer! Nu tijd voor wat `ggplots`! Dus welke `geom` gaan we gebruiken?\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": [
|
|
"Easy-gg!\n",
|
|
"\n",
|
|
"Nu kunnen we zien dat deze gegevens een beetje rommelig zijn: door elke kolom als een boxplot te bekijken, kun je uitschieters zien. Je zou door de dataset kunnen gaan en deze uitschieters verwijderen, maar dat zou de gegevens erg minimaal maken.\n",
|
|
"\n",
|
|
"Laten we voorlopig kiezen welke kolommen we gaan gebruiken voor onze clusteringoefening. Laten we de numerieke kolommen met vergelijkbare bereiken kiezen. We zouden `artist_top_genre` als numeriek kunnen coderen, maar we laten het voorlopig vallen.\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. Het berekenen van k-means clustering in R\n",
|
|
"\n",
|
|
"We kunnen k-means in R berekenen met de ingebouwde functie `kmeans`, zie `help(\"kmeans()\")`. De functie `kmeans()` accepteert een data frame met alleen numerieke kolommen als zijn belangrijkste argument.\n",
|
|
"\n",
|
|
"De eerste stap bij het gebruik van k-means clustering is het specificeren van het aantal clusters (k) dat in de uiteindelijke oplossing zal worden gegenereerd. We weten dat er 3 muziekgenres zijn die we uit de dataset hebben gehaald, dus laten we 3 proberen:\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": [
|
|
"Het kmeans-object bevat verschillende informatie die goed wordt uitgelegd in `help(\"kmeans()\")`. Laten we ons voorlopig op een paar punten concentreren. We zien dat de data is gegroepeerd in 3 clusters met groottes van 65, 110, 111. De output bevat ook de clustercentra (gemiddelden) voor de 3 groepen over de 5 variabelen.\n",
|
|
"\n",
|
|
"De clusteringvector is de clusterindeling voor elke observatie. Laten we de functie `augment` gebruiken om de clusterindeling toe te voegen aan de oorspronkelijke dataset.\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": [
|
|
"Perfect, we hebben zojuist onze dataset opgedeeld in een set van 3 groepen. Dus, hoe goed is onze clustering 🤷? Laten we eens kijken naar de `Silhouette score`.\n",
|
|
"\n",
|
|
"### **Silhouette score**\n",
|
|
"\n",
|
|
"[Silhouette-analyse](https://en.wikipedia.org/wiki/Silhouette_(clustering)) kan worden gebruikt om de scheidingsafstand tussen de resulterende clusters te bestuderen. Deze score varieert van -1 tot 1, en als de score dicht bij 1 ligt, is het cluster compact en goed gescheiden van andere clusters. Een waarde dicht bij 0 vertegenwoordigt overlappende clusters met samples die zich dicht bij de beslissingsgrens van de naburige clusters bevinden. [bron](https://dzone.com/articles/kmeans-silhouette-score-explained-with-python-exam).\n",
|
|
"\n",
|
|
"De gemiddelde silhouette-methode berekent de gemiddelde silhouette van observaties voor verschillende waarden van *k*. Een hoge gemiddelde silhouette-score wijst op een goede clustering.\n",
|
|
"\n",
|
|
"De `silhouette`-functie in het clusterpakket wordt gebruikt om de gemiddelde silhouette-breedte te berekenen.\n",
|
|
"\n",
|
|
"> De silhouette kan worden berekend met elke [afstand](https://en.wikipedia.org/wiki/Distance \"Distance\")-metric, zoals de [Euclidische afstand](https://en.wikipedia.org/wiki/Euclidean_distance \"Euclidean distance\") of de [Manhattan afstand](https://en.wikipedia.org/wiki/Manhattan_distance \"Manhattan distance\") die we hebben besproken in de [vorige les](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": [
|
|
"Onze score is **.549**, dus precies in het midden. Dit geeft aan dat onze data niet bijzonder geschikt is voor dit type clustering. Laten we kijken of we dit vermoeden visueel kunnen bevestigen. Het [factoextra-pakket](https://rpkgs.datanovia.com/factoextra/index.html) biedt functies (`fviz_cluster()`) om clustering te visualiseren.\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": [
|
|
"De overlap in clusters geeft aan dat onze data niet bijzonder geschikt is voor dit type clustering, maar laten we doorgaan.\n",
|
|
"\n",
|
|
"## 4. Bepalen van het optimale aantal clusters\n",
|
|
"\n",
|
|
"Een fundamentele vraag die vaak opkomt bij K-Means clustering is deze: zonder bekende klassenlabels, hoe weet je in hoeveel clusters je je data moet verdelen?\n",
|
|
"\n",
|
|
"Een manier om dit te achterhalen is door een steekproef van de data te gebruiken om `een reeks clusteringmodellen te maken` met een oplopend aantal clusters (bijvoorbeeld van 1-10), en clusteringstatistieken zoals de **Silhouettescore** te evalueren.\n",
|
|
"\n",
|
|
"Laten we het optimale aantal clusters bepalen door het clustering-algoritme te berekenen voor verschillende waarden van *k* en de **Within Cluster Sum of Squares** (WCSS) te evalueren. De totale binnen-cluster som van kwadraten (WCSS) meet de compactheid van de clustering en we willen dat deze zo klein mogelijk is, waarbij lagere waarden betekenen dat de datapunten dichter bij elkaar liggen.\n",
|
|
"\n",
|
|
"Laten we het effect van verschillende keuzes van `k`, van 1 tot 10, op deze clustering onderzoeken.\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": [
|
|
"Nu we de totale binnen-cluster som van kwadraten (tot.withinss) hebben voor elk clustering-algoritme met centrum *k*, gebruiken we de [elleboogmethode](https://en.wikipedia.org/wiki/Elbow_method_(clustering)) om het optimale aantal clusters te bepalen. Deze methode houdt in dat we de WCSS uitzetten als een functie van het aantal clusters, en het [elleboogpunt van de curve](https://en.wikipedia.org/wiki/Elbow_of_the_curve \"Ellebogpunt van de curve\") kiezen als het aantal clusters dat we moeten gebruiken.\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": [
|
|
"De grafiek toont een grote afname in WCSS (dus grotere *compactheid*) wanneer het aantal clusters toeneemt van één naar twee, en een verdere duidelijke afname van twee naar drie clusters. Daarna wordt de afname minder uitgesproken, wat resulteert in een `knikpunt` 💪 in de grafiek rond drie clusters. Dit is een goede indicatie dat er twee tot drie redelijk goed gescheiden clusters van datapunten zijn.\n",
|
|
"\n",
|
|
"We kunnen nu verdergaan en het clusteringmodel extraheren waar `k = 3`:\n",
|
|
"\n",
|
|
"> `pull()`: gebruikt om een enkele kolom te extraheren\n",
|
|
">\n",
|
|
"> `pluck()`: gebruikt om datastructuren zoals lijsten te indexeren\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": [
|
|
"Geweldig! Laten we de verkregen clusters visualiseren. Zin in wat interactie met `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": [
|
|
"Misschien hadden we verwacht dat elke cluster (weergegeven door verschillende kleuren) unieke genres zou hebben (weergegeven door verschillende vormen).\n",
|
|
"\n",
|
|
"Laten we de nauwkeurigheid van het model bekijken.\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": [
|
|
"De nauwkeurigheid van dit model is niet slecht, maar ook niet geweldig. Het kan zijn dat de data niet goed geschikt is voor K-Means Clustering. Deze data is te onevenwichtig, te weinig gecorreleerd en er is te veel variatie tussen de kolomwaarden om goed te clusteren. Sterker nog, de clusters die gevormd worden, worden waarschijnlijk sterk beïnvloed of vertekend door de drie genrecategorieën die we hierboven hebben gedefinieerd.\n",
|
|
"\n",
|
|
"Desondanks was dit een leerzaam proces!\n",
|
|
"\n",
|
|
"In de documentatie van Scikit-learn kun je zien dat een model zoals dit, met clusters die niet goed afgebakend zijn, een 'variantie'-probleem heeft:\n",
|
|
"\n",
|
|
"<p >\n",
|
|
" <img src=\"../../images/problems.png\"\n",
|
|
" width=\"500\"/>\n",
|
|
" <figcaption>Infographic van Scikit-learn</figcaption>\n",
|
|
"\n",
|
|
"\n",
|
|
"\n",
|
|
"## **Variantie**\n",
|
|
"\n",
|
|
"Variantie wordt gedefinieerd als \"het gemiddelde van de kwadratische verschillen ten opzichte van het gemiddelde\" [bron](https://www.mathsisfun.com/data/standard-deviation.html). In de context van dit clusteringprobleem verwijst het naar data waarbij de waarden in onze dataset de neiging hebben om te veel af te wijken van het gemiddelde.\n",
|
|
"\n",
|
|
"✅ Dit is een goed moment om na te denken over alle manieren waarop je dit probleem kunt corrigeren. Kun je de data nog wat aanpassen? Andere kolommen gebruiken? Een ander algoritme proberen? Tip: Probeer [je data te schalen](https://www.mygreatlearning.com/blog/learning-data-science-with-k-means-clustering/) om het te normaliseren en test andere kolommen.\n",
|
|
"\n",
|
|
"> Probeer deze '[variantiecalculator](https://www.calculatorsoup.com/calculators/statistics/variance-calculator.php)' om het concept beter te begrijpen.\n",
|
|
"\n",
|
|
"------------------------------------------------------------------------\n",
|
|
"\n",
|
|
"## **🚀Uitdaging**\n",
|
|
"\n",
|
|
"Besteed wat tijd aan deze notebook en pas parameters aan. Kun je de nauwkeurigheid van het model verbeteren door de data verder op te schonen (bijvoorbeeld door uitschieters te verwijderen)? Je kunt gewichten gebruiken om bepaalde data samples meer gewicht te geven. Wat kun je nog meer doen om betere clusters te creëren?\n",
|
|
"\n",
|
|
"Tip: Probeer je data te schalen. Er staat gecommentarieerde code in de notebook die standaard schaling toevoegt om de datakolommen meer op elkaar te laten lijken qua bereik. Je zult merken dat terwijl de silhouette score daalt, de 'knik' in de ellebooggrafiek gladder wordt. Dit komt omdat het niet schalen van de data ervoor zorgt dat data met minder variatie meer gewicht krijgt. Lees meer over dit probleem [hier](https://stats.stackexchange.com/questions/21222/are-mean-normalization-and-feature-scaling-needed-for-k-means-clustering/21226#21226).\n",
|
|
"\n",
|
|
"## [**Quiz na de les**](https://gray-sand-07a10f403.1.azurestaticapps.net/quiz/30/)\n",
|
|
"\n",
|
|
"## **Review & Zelfstudie**\n",
|
|
"\n",
|
|
"- Bekijk een K-Means Simulator [zoals deze](https://user.ceng.metu.edu.tr/~akifakkus/courses/ceng574/k-means/). Je kunt deze tool gebruiken om voorbeelddatapunten te visualiseren en de centra ervan te bepalen. Je kunt de willekeurigheid van de data, het aantal clusters en het aantal centra aanpassen. Helpt dit je om een idee te krijgen van hoe de data gegroepeerd kan worden?\n",
|
|
"\n",
|
|
"- Bekijk ook [deze hand-out over K-Means](https://stanford.edu/~cpiech/cs221/handouts/kmeans.html) van Stanford.\n",
|
|
"\n",
|
|
"Wil je je nieuw verworven clusteringvaardigheden toepassen op datasets die goed geschikt zijn voor K-Means clustering? Bekijk dan:\n",
|
|
"\n",
|
|
"- [Train and Evaluate Clustering Models](https://rpubs.com/eR_ic/clustering) met behulp van Tidymodels en vrienden\n",
|
|
"\n",
|
|
"- [K-means Cluster Analysis](https://uc-r.github.io/kmeans_clustering), UC Business Analytics R Programming Guide\n",
|
|
"\n",
|
|
"- [K-means clustering met tidy data principes](https://www.tidymodels.org/learn/statistics/k-means/)\n",
|
|
"\n",
|
|
"## **Opdracht**\n",
|
|
"\n",
|
|
"[Probeer verschillende clusteringmethoden](https://github.com/microsoft/ML-For-Beginners/blob/main/5-Clustering/2-K-Means/assignment.md)\n",
|
|
"\n",
|
|
"## BEDANKT AAN:\n",
|
|
"\n",
|
|
"[Jen Looper](https://www.twitter.com/jenlooper) voor het maken van de originele Python-versie van deze module ♥️\n",
|
|
"\n",
|
|
"[`Allison Horst`](https://twitter.com/allison_horst/) voor het maken van de geweldige illustraties die R toegankelijker en aantrekkelijker maken. Vind meer illustraties in haar [galerij](https://www.google.com/url?q=https://github.com/allisonhorst/stats-illustrations&sa=D&source=editors&ust=1626380772530000&usg=AOvVaw3zcfyCizFQZpkSLzxiiQEM).\n",
|
|
"\n",
|
|
"Veel leerplezier,\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>Illustratie door @allison_horst</figcaption>\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"\n---\n\n**Disclaimer**: \nDit document is vertaald met behulp van de AI-vertalingsservice [Co-op Translator](https://github.com/Azure/co-op-translator). Hoewel we streven naar nauwkeurigheid, willen we u erop wijzen dat geautomatiseerde vertalingen fouten of onnauwkeurigheden kunnen bevatten. Het originele document in de oorspronkelijke taal moet worden beschouwd als de gezaghebbende bron. Voor kritieke informatie wordt professionele menselijke vertaling aanbevolen. Wij zijn niet aansprakelijk voor misverstanden of verkeerde interpretaties die voortvloeien uit het gebruik van deze vertaling.\n"
|
|
]
|
|
}
|
|
]
|
|
} |