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.
ML-For-Beginners/translations/he/5-Clustering/2-K-Means/solution/R/lesson_15-R.ipynb

637 lines
31 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

{
"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-04T08:11:41+00:00",
"source_file": "5-Clustering/2-K-Means/solution/R/lesson_15-R.ipynb",
"language_code": "he"
}
},
"cells": [
{
"cell_type": "markdown",
"metadata": {
"id": "GULATlQXLXyR"
},
"source": [
"## חקר אשכולות K-Means באמצעות R ועקרונות נתונים מסודרים\n",
"\n",
"### [**שאלון לפני השיעור**](https://gray-sand-07a10f403.1.azurestaticapps.net/quiz/29/)\n",
"\n",
"בשיעור זה תלמדו כיצד ליצור אשכולות באמצעות חבילת Tidymodels וחבילות נוספות באקוסיסטם של R (נקרא להן חברים 🧑‍🤝‍🧑), תוך שימוש במאגר הנתונים של מוזיקה ניגרית שייבאתם קודם לכן. נסקור את היסודות של K-Means לאשכולות. זכרו, כפי שלמדתם בשיעור הקודם, ישנן דרכים רבות לעבוד עם אשכולות, והשיטה שתבחרו תלויה בנתונים שלכם. ננסה את K-Means מכיוון שזו טכניקת האשכולות הנפוצה ביותר. בואו נתחיל!\n",
"\n",
"מונחים שתלמדו עליהם:\n",
"\n",
"- ניקוד סילואט (Silhouette scoring)\n",
"\n",
"- שיטת המרפק (Elbow method)\n",
"\n",
"- אינרציה (Inertia)\n",
"\n",
"- שונות (Variance)\n",
"\n",
"### **מבוא**\n",
"\n",
"[אשכולות K-Means](https://wikipedia.org/wiki/K-means_clustering) היא שיטה שמקורה בתחום עיבוד האותות. היא משמשת לחלוקה וקיבוץ של נתונים ל-`k אשכולות` בהתבסס על דמיון בתכונותיהם.\n",
"\n",
"ניתן להמחיש את האשכולות כ-[דיאגרמות וורונוי](https://wikipedia.org/wiki/Voronoi_diagram), הכוללות נקודה (או 'זרע') והאזור המתאים לה.\n",
"\n",
"<p >\n",
" <img src=\"../../images/voronoi.png\"\n",
" width=\"500\"/>\n",
" <figcaption>אינפוגרפיקה מאת ג'ן לופר</figcaption>\n",
"\n",
"תהליך אשכולות K-Means כולל את השלבים הבאים:\n",
"\n",
"1. מדען הנתונים מתחיל בקביעת מספר האשכולות הרצוי ליצירה.\n",
"\n",
"2. לאחר מכן, האלגוריתם בוחר באופן אקראי K תצפיות ממאגר הנתונים שישמשו כמרכזים הראשוניים של האשכולות (כלומר, צנטרואידים).\n",
"\n",
"3. לאחר מכן, כל אחת מהתצפיות הנותרות מוקצת לצנטרואיד הקרוב ביותר.\n",
"\n",
"4. לאחר מכן, מחושב הממוצע החדש של כל אשכול, והצנטרואיד מועבר לממוצע.\n",
"\n",
"5. כעת, לאחר שחושבו מחדש המרכזים, נבדקת שוב כל תצפית כדי לראות אם היא קרובה יותר לאשכול אחר. כל האובייקטים מוקצים מחדש תוך שימוש בממוצעי האשכולות המעודכנים. שלבי הקצאת האשכולות ועדכון הצנטרואידים חוזרים על עצמם באופן איטרטיבי עד שהקצאות האשכולות מפסיקות להשתנות (כלומר, כאשר מושגת התכנסות). בדרך כלל, האלגוריתם מסתיים כאשר כל איטרציה חדשה מביאה לתנועה זניחה של הצנטרואידים והאשכולות הופכים לסטטיים.\n",
"\n",
"<div>\n",
"\n",
"> שימו לב שבשל האקראיות בבחירת k התצפיות הראשוניות כצנטרואידים ההתחלתיים, אנו עשויים לקבל תוצאות מעט שונות בכל פעם שניישם את התהליך. מסיבה זו, רוב האלגוריתמים משתמשים בכמה *התחלות אקראיות* ובוחרים את האיטרציה עם ה-WCSS הנמוך ביותר. לכן, מומלץ בחום להריץ תמיד את K-Means עם כמה ערכים של *nstart* כדי להימנע מ-*מינימום מקומי בלתי רצוי.*\n",
"\n",
"</div>\n",
"\n",
"אנימציה קצרה זו, המשתמשת ב-[איורים](https://github.com/allisonhorst/stats-illustrations) של אליסון הורסט, מסבירה את תהליך האשכולות:\n",
"\n",
"<p >\n",
" <img src=\"../../images/kmeans.gif\"\n",
" width=\"550\"/>\n",
" <figcaption>איור מאת @allison_horst</figcaption>\n",
"\n",
"שאלה בסיסית שעולה באשכולות היא: איך יודעים לכמה אשכולות לחלק את הנתונים? חיסרון אחד של שימוש ב-K-Means הוא שתצטרכו לקבוע את `k`, כלומר את מספר ה-`צנטרואידים`. למרבה המזל, `שיטת המרפק` עוזרת להעריך ערך התחלתי טוב עבור `k`. תנסו זאת בעוד רגע.\n",
"\n",
"### \n",
"\n",
"**דרישות מוקדמות**\n",
"\n",
"נמשיך בדיוק מהמקום שבו עצרנו ב-[שיעור הקודם](https://github.com/microsoft/ML-For-Beginners/blob/main/5-Clustering/1-Visualize/solution/R/lesson_14-R.ipynb), שבו ניתחנו את מאגר הנתונים, יצרנו המון ויזואליזציות וסיננו את הנתונים לתצפיות מעניינות. ודאו שבדקתם אותו!\n",
"\n",
"נזדקק לכמה חבילות כדי להשלים את המודול הזה. ניתן להתקין אותן כך: `install.packages(c('tidyverse', 'tidymodels', 'cluster', 'summarytools', 'plotly', 'paletteer', 'factoextra', 'patchwork'))`\n",
"\n",
"לחילופין, הסקריפט הבא בודק אם יש לכם את החבילות הנדרשות להשלמת המודול ומתקין אותן עבורכם במקרה שחסרות:\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": [
"בואו נתחיל!\n",
"\n",
"## 1. ריקוד עם נתונים: צמצום ל-3 הז'אנרים המוזיקליים הפופולריים ביותר\n",
"\n",
"זהו סיכום של מה שעשינו בשיעור הקודם. בואו נחתוך וננתח קצת נתונים!\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": [
"🤩 זה הלך טוב!\n",
"\n",
"## 2. חקירת נתונים נוספת.\n",
"\n",
"כמה נקיים הנתונים האלה? בואו נבדוק חריגות באמצעות תרשימי קופסה. נתמקד בעמודות מספריות עם פחות חריגות (למרות שאתם יכולים לנקות את החריגות). תרשימי קופסה יכולים להראות את טווח הנתונים ויעזרו לבחור אילו עמודות להשתמש. שימו לב, תרשימי קופסה אינם מציגים שונות, שהיא מרכיב חשוב בנתונים שניתן לקבץ בצורה טובה. אנא ראו [דיון זה](https://stats.stackexchange.com/questions/91536/deduce-variance-from-boxplot) לקריאה נוספת.\n",
"\n",
"[תרשימי קופסה](https://en.wikipedia.org/wiki/Box_plot) משמשים לתיאור גרפי של התפלגות נתונים `מספריים`, אז בואו נתחיל ב*בחירת* כל העמודות המספריות לצד ז'אנרי המוזיקה הפופולריים.\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": [
"ראו כיצד הפונקציה `where` עוזרת בבחירה בצורה פשוטה 💁? תוכלו לחקור פונקציות נוספות [כאן](https://tidyselect.r-lib.org/).\n",
"\n",
"מכיוון שניצור תרשים תיבות עבור כל מאפיין מספרי ורוצים להימנע משימוש בלולאות, נשנה את מבנה הנתונים שלנו לפורמט *ארוך* יותר, שיאפשר לנו לנצל את `facets` - תת-תרשימים שכל אחד מהם מציג תת-קבוצה של הנתונים.\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": []
},
{
"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": [
"קל-ג'י-ג'י!\n",
"\n",
"עכשיו אנחנו יכולים לראות שהנתונים מעט רועשים: על ידי התבוננות בכל עמודה כגרף קופסה, ניתן להבחין בערכים חריגים. אפשר לעבור על מערך הנתונים ולהסיר את הערכים החריגים הללו, אבל זה יהפוך את הנתונים למינימליים מאוד.\n",
"\n",
"בשלב זה, בואו נבחר אילו עמודות נשתמש בתרגיל האשכולות שלנו. נבחר את העמודות המספריות עם טווחים דומים. אפשר לקודד את `artist_top_genre` כערך מספרי, אבל כרגע נוותר עליו.\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. חישוב אשכולות k-means ב-R\n",
"\n",
"ניתן לחשב k-means ב-R באמצעות הפונקציה המובנית `kmeans`, ראו `help(\"kmeans()\")`. הפונקציה `kmeans()` מקבלת מסגרת נתונים עם עמודות מספריות בלבד כארגומנט הראשי שלה.\n",
"\n",
"השלב הראשון בשימוש באשכולות k-means הוא לקבוע את מספר האשכולות (k) שייווצרו בפתרון הסופי. אנחנו יודעים שיש 3 ז'אנרים של שירים שזיהינו מתוך מערך הנתונים, אז בואו ננסה 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": [
"אובייקט ה-kmeans מכיל מספר פרטי מידע שמוסברים היטב ב-`help(\"kmeans()\")`. כרגע, נתמקד בכמה מהם. אנו רואים שהנתונים חולקו ל-3 אשכולות בגודל 65, 110, 111. הפלט גם מכיל את מרכזי האשכולות (ממוצעים) עבור 3 הקבוצות על פני 5 המשתנים.\n",
"\n",
"וקטור האשכולות הוא שיוך האשכול עבור כל תצפית. בואו נשתמש בפונקציה `augment` כדי להוסיף את שיוך האשכול לסט הנתונים המקורי.\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": [
"מעולה, חילקנו את מערך הנתונים שלנו ל-3 קבוצות. אז, עד כמה טובה החלוקה שלנו 🤷? בואו נבחן את `ציון הסילואט`.\n",
"\n",
"### **ציון הסילואט**\n",
"\n",
"[ניתוח סילואט](https://en.wikipedia.org/wiki/Silhouette_(clustering)) יכול לשמש כדי לבחון את מרחק ההפרדה בין הקבוצות שהתקבלו. ציון זה נע בין -1 ל-1, ואם הציון קרוב ל-1, הקבוצה צפופה ומופרדת היטב מקבוצות אחרות. ערך קרוב ל-0 מייצג קבוצות חופפות עם דגימות קרובות מאוד לגבול ההחלטה של הקבוצות השכנות. [מקור](https://dzone.com/articles/kmeans-silhouette-score-explained-with-python-exam).\n",
"\n",
"שיטת הסילואט הממוצע מחשבת את ממוצע הסילואט של התצפיות עבור ערכים שונים של *k*. ציון סילואט ממוצע גבוה מעיד על חלוקה טובה.\n",
"\n",
"הפונקציה `silhouette` בחבילת ה-cluster משמשת לחישוב רוחב הסילואט הממוצע.\n",
"\n",
"> ניתן לחשב את הסילואט עם כל [מדד מרחק](https://en.wikipedia.org/wiki/Distance \"Distance\"), כמו [מרחק אוקלידי](https://en.wikipedia.org/wiki/Euclidean_distance \"Euclidean distance\") או [מרחק מנהטן](https://en.wikipedia.org/wiki/Manhattan_distance \"Manhattan distance\") שדנו בהם ב[שיעור הקודם](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": [
"הציון שלנו הוא **.549**, כלומר ממש באמצע. זה מצביע על כך שהנתונים שלנו לא מתאימים במיוחד לסוג זה של אשכולות. בואו נראה אם נוכל לאשר את ההשערה הזו באופן חזותי. [חבילת factoextra](https://rpkgs.datanovia.com/factoextra/index.html) מספקת פונקציות (`fviz_cluster()`) כדי להמחיש אשכולות.\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": [
"החפיפה בין הקבוצות מצביעה על כך שהנתונים שלנו אינם מתאימים במיוחד לסוג זה של אשכולות, אך בואו נמשיך.\n",
"\n",
"## 4. קביעת מספר האשכולות האופטימלי\n",
"\n",
"שאלה בסיסית שעולה לעיתים קרובות באשכולות K-Means היא זו - ללא תוויות מחלקה ידועות, איך יודעים לכמה אשכולות יש לחלק את הנתונים?\n",
"\n",
"אחת הדרכים לנסות לגלות זאת היא להשתמש בדגימת נתונים כדי `ליצור סדרה של מודלים אשכוליים` עם מספר אשכולות הולך וגדל (לדוגמה, מ-1 עד 10), ולהעריך מדדי אשכולות כמו **ציון הסילואט.**\n",
"\n",
"בואו נקבע את מספר האשכולות האופטימלי על ידי חישוב האלגוריתם האשכולי עבור ערכים שונים של *k* והערכת **סכום הריבועים בתוך האשכולות** (WCSS). סכום הריבועים הכולל בתוך האשכולות (WCSS) מודד את הקומפקטיות של האשכולות, ואנו רוצים שהוא יהיה קטן ככל האפשר, כאשר ערכים נמוכים מצביעים על כך שנקודות הנתונים קרובות יותר.\n",
"\n",
"בואו נחקור את ההשפעה של בחירות שונות של `k`, מ-1 עד 10, על האשכולות הללו.\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": [
"עכשיו, כשיש לנו את סכום הריבועים בתוך הקבוצה הכולל (tot.withinss) עבור כל אלגוריתם אשכולות עם מרכז *k*, אנו משתמשים בשיטת [המרפק](https://en.wikipedia.org/wiki/Elbow_method_(clustering)) כדי למצוא את מספר האשכולות האופטימלי. השיטה כוללת שרטוט של WCSS כפונקציה של מספר האשכולות, ובחירת [המרפק של העקומה](https://en.wikipedia.org/wiki/Elbow_of_the_curve \"Elbow of the curve\") כמספר האשכולות לשימוש.\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": [
"הגרף מציג ירידה משמעותית ב-WCSS (כלומר, *צפיפות* גבוהה יותר) כאשר מספר האשכולות עולה מאחד לשניים, וירידה נוספת ניכרת משניים לשלושה אשכולות. לאחר מכן, הירידה פחות בולטת, מה שיוצר \"מרפק\" 💪 בגרף בסביבות שלושה אשכולות. זהו סימן טוב לכך שישנם שניים עד שלושה אשכולות של נקודות נתונים המופרדים באופן סביר.\n",
"\n",
"כעת נוכל להמשיך ולחלץ את מודל האשכולות שבו `k = 3`:\n",
"\n",
"> `pull()`: משמש לחילוץ עמודה בודדת \n",
"> \n",
"> `pluck()`: משמש לאינדוקס מבני נתונים כמו רשימות \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": [
"מעולה! בואו נתקדם ונתבונן באשכולות שהתקבלו. מעוניינים להוסיף קצת אינטראקטיביות באמצעות `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": [
"אולי היינו מצפים שלכל אשכול (המוצג בצבעים שונים) יהיו ז'אנרים מובחנים (המוצגים בצורות שונות).\n",
"\n",
"בואו נבחן את דיוק המודל.\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": [
"הדיוק של המודל הזה לא רע, אבל גם לא מצוין. ייתכן שהנתונים אינם מתאימים היטב לקיבוץ באמצעות K-Means Clustering. הנתונים הללו אינם מאוזנים, הקורלציה ביניהם נמוכה מדי ויש יותר מדי שונות בין ערכי העמודות כדי ליצור קיבוץ מוצלח. למעשה, הקבוצות שנוצרות כנראה מושפעות או מוטות מאוד על ידי שלוש קטגוריות הז'אנר שהגדרנו קודם.\n",
"\n",
"עם זאת, זו הייתה חוויה לימודית משמעותית!\n",
"\n",
"בתיעוד של Scikit-learn, ניתן לראות שמודל כמו זה, שבו הקבוצות אינן מוגדרות היטב, סובל מבעיה של 'שונות':\n",
"\n",
"<p >\n",
" <img src=\"../../images/problems.png\"\n",
" width=\"500\"/>\n",
" <figcaption>אינפוגרפיקה מתוך Scikit-learn</figcaption>\n",
"\n",
"\n",
"\n",
"## **שונות**\n",
"\n",
"שונות מוגדרת כ\"הממוצע של ריבועי ההבדלים מהממוצע\" [מקור](https://www.mathsisfun.com/data/standard-deviation.html). בהקשר של בעיית הקיבוץ הזו, היא מתייחסת לנתונים שבהם הערכים של מערך הנתונים שלנו נוטים לסטות יותר מדי מהממוצע.\n",
"\n",
"✅ זהו רגע מצוין לחשוב על כל הדרכים שבהן ניתן לתקן את הבעיה הזו. לשנות מעט את הנתונים? להשתמש בעמודות אחרות? להשתמש באלגוריתם שונה? רמז: נסו [לשנות את קנה המידה של הנתונים](https://www.mygreatlearning.com/blog/learning-data-science-with-k-means-clustering/) כדי לנרמל אותם ולבדוק עמודות אחרות.\n",
"\n",
"> נסו את '[מחשבון השונות](https://www.calculatorsoup.com/calculators/statistics/variance-calculator.php)' כדי להבין את המושג קצת יותר.\n",
"\n",
"------------------------------------------------------------------------\n",
"\n",
"## **🚀אתגר**\n",
"\n",
"הקדישו זמן למחברת הזו ושנו פרמטרים. האם תוכלו לשפר את דיוק המודל על ידי ניקוי הנתונים יותר (למשל, הסרת ערכים חריגים)? תוכלו להשתמש במשקלים כדי לתת משקל רב יותר לדגימות נתונים מסוימות. מה עוד תוכלו לעשות כדי ליצור קבוצות טובות יותר?\n",
"\n",
"רמז: נסו לשנות את קנה המידה של הנתונים. יש קוד עם הערות במחברת שמוסיף שינוי קנה מידה סטנדרטי כדי לגרום לעמודות הנתונים להיות דומות יותר זו לזו מבחינת טווח. תגלו שבעוד שהציון של הסילואט יורד, ה'שבר' בגרף המרפק מתיישר. זאת משום שהשארת הנתונים ללא שינוי קנה מידה מאפשרת לנתונים עם פחות שונות לקבל משקל רב יותר. קראו עוד על הבעיה הזו [כאן](https://stats.stackexchange.com/questions/21222/are-mean-normalization-and-feature-scaling-needed-for-k-means-clustering/21226#21226).\n",
"\n",
"## [**שאלון לאחר ההרצאה**](https://gray-sand-07a10f403.1.azurestaticapps.net/quiz/30/)\n",
"\n",
"## **סקירה ולימוד עצמי**\n",
"\n",
"- הסתכלו על סימולטור K-Means [כמו זה](https://user.ceng.metu.edu.tr/~akifakkus/courses/ceng574/k-means/). תוכלו להשתמש בכלי הזה כדי להמחיש נקודות נתונים לדוגמה ולקבוע את המרכזים שלהן. תוכלו לערוך את רמת האקראיות של הנתונים, מספר הקבוצות ומספר המרכזים. האם זה עוזר לכם להבין כיצד ניתן לקבץ את הנתונים?\n",
"\n",
"- בנוסף, הסתכלו על [המסמך הזה על K-Means](https://stanford.edu/~cpiech/cs221/handouts/kmeans.html) מאוניברסיטת סטנפורד.\n",
"\n",
"רוצים לנסות את כישורי הקיבוץ החדשים שלכם על מערכי נתונים שמתאימים היטב ל-K-Means Clustering? ראו:\n",
"\n",
"- [אימון והערכת מודלים של קיבוץ](https://rpubs.com/eR_ic/clustering) באמצעות Tidymodels וחברים\n",
"\n",
"- [ניתוח קיבוץ K-Means](https://uc-r.github.io/kmeans_clustering), מדריך לתכנות R של UC Business Analytics\n",
"\n",
"- [קיבוץ K-Means עם עקרונות נתונים מסודרים](https://www.tidymodels.org/learn/statistics/k-means/)\n",
"\n",
"## **משימה**\n",
"\n",
"[נסו שיטות קיבוץ שונות](https://github.com/microsoft/ML-For-Beginners/blob/main/5-Clustering/2-K-Means/assignment.md)\n",
"\n",
"## תודה ל:\n",
"\n",
"[Jen Looper](https://www.twitter.com/jenlooper) על יצירת הגרסה המקורית של המודול הזה בפייתון ♥️\n",
"\n",
"[`Allison Horst`](https://twitter.com/allison_horst/) על יצירת האיורים המדהימים שהופכים את R למזמין ומרתק יותר. מצאו איורים נוספים בגלריה שלה [כאן](https://www.google.com/url?q=https://github.com/allisonhorst/stats-illustrations&sa=D&source=editors&ust=1626380772530000&usg=AOvVaw3zcfyCizFQZpkSLzxiiQEM).\n",
"\n",
"למידה נעימה,\n",
"\n",
"[Eric](https://twitter.com/ericntay), שגריר סטודנטים של Microsoft Learn.\n",
"\n",
"<p >\n",
" <img src=\"../../images/r_learners_sm.jpeg\"\n",
" width=\"500\"/>\n",
" <figcaption>יצירה מאת @allison_horst</figcaption>\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n---\n\n**כתב ויתור**: \nמסמך זה תורגם באמצעות שירות תרגום מבוסס בינה מלאכותית [Co-op Translator](https://github.com/Azure/co-op-translator). למרות שאנו שואפים לדיוק, יש לקחת בחשבון שתרגומים אוטומטיים עשויים להכיל שגיאות או אי-דיוקים. המסמך המקורי בשפתו המקורית נחשב למקור הסמכותי. למידע קריטי, מומלץ להשתמש בתרגום מקצועי על ידי מתרגם אנושי. איננו נושאים באחריות לכל אי-הבנה או פרשנות שגויה הנובעת משימוש בתרגום זה. \n"
]
}
]
}