{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "## בניית מודל רגרסיה לוגיסטית - שיעור 4\n", "\n", "![אינפוגרפיקה של רגרסיה לוגיסטית מול רגרסיה ליניארית](../../../../../../2-Regression/4-Logistic/images/linear-vs-logistic.png)\n", "\n", "#### **[שאלון לפני השיעור](https://gray-sand-07a10f403.1.azurestaticapps.net/quiz/15/)**\n", "\n", "#### מבוא\n", "\n", "בשיעור האחרון על רגרסיה, אחת מטכניקות ה-ML הקלאסיות הבסיסיות, נבחן את רגרסיה לוגיסטית. תשתמשו בטכניקה זו כדי לזהות דפוסים ולחזות קטגוריות בינאריות. האם הממתק הזה הוא שוקולד או לא? האם המחלה הזו מדבקת או לא? האם הלקוח הזה יבחר במוצר הזה או לא?\n", "\n", "בשיעור זה תלמדו:\n", "\n", "- טכניקות לרגרסיה לוגיסטית\n", "\n", "✅ העמיקו את ההבנה שלכם בעבודה עם סוג זה של רגרסיה במודול [Learn](https://learn.microsoft.com/training/modules/introduction-classification-models/?WT.mc_id=academic-77952-leestott)\n", "\n", "## דרישות מקדימות\n", "\n", "לאחר שעבדנו עם נתוני הדלעת, אנחנו כבר מספיק מכירים אותם כדי להבין שיש קטגוריה בינארית אחת שנוכל לעבוד איתה: `Color`.\n", "\n", "בואו נבנה מודל רגרסיה לוגיסטית כדי לחזות, בהתבסס על משתנים מסוימים, *איזה צבע צפוי להיות לדלעת מסוימת* (כתום 🎃 או לבן 👻).\n", "\n", "> למה אנחנו מדברים על סיווג בינארי בשיעור שמקושר לרגרסיה? רק מטעמי נוחות לשונית, שכן רגרסיה לוגיסטית היא [בעצם שיטת סיווג](https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression), אם כי מבוססת ליניארית. למדו על דרכים אחרות לסווג נתונים בקבוצת השיעורים הבאה.\n", "\n", "לשיעור זה נצטרך את החבילות הבאות:\n", "\n", "- `tidyverse`: [tidyverse](https://www.tidyverse.org/) הוא [אוסף של חבילות R](https://www.tidyverse.org/packages) שנועד להפוך את מדע הנתונים למהיר, קל ומהנה יותר!\n", "\n", "- `tidymodels`: [מסגרת tidymodels](https://www.tidymodels.org/) היא [אוסף של חבילות](https://www.tidymodels.org/packages/) למידול ולמידת מכונה.\n", "\n", "- `janitor`: [חבילת janitor](https://github.com/sfirke/janitor) מספקת כלים פשוטים לבחינה וניקוי של נתונים מלוכלכים.\n", "\n", "- `ggbeeswarm`: [חבילת ggbeeswarm](https://github.com/eclarke/ggbeeswarm) מספקת שיטות ליצירת גרפים בסגנון beeswarm באמצעות ggplot2.\n", "\n", "ניתן להתקין אותן כך:\n", "\n", "`install.packages(c(\"tidyverse\", \"tidymodels\", \"janitor\", \"ggbeeswarm\"))`\n", "\n", "לחילופין, הסקריפט הבא בודק אם יש לכם את החבילות הנדרשות להשלמת מודול זה ומתקין אותן עבורכם במקרה שחסרות.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "suppressWarnings(if (!require(\"pacman\"))install.packages(\"pacman\"))\n", "\n", "pacman::p_load(tidyverse, tidymodels, janitor, ggbeeswarm)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## **הגדרת השאלה**\n", "\n", "למטרותינו, נבטא זאת כבינארי: 'לבן' או 'לא לבן'. יש גם קטגוריה של 'מפוספס' במאגר הנתונים שלנו, אך יש מעט מקרים שלה, ולכן לא נשתמש בה. היא נעלמת בכל מקרה כשאנחנו מסירים ערכים חסרים מהמאגר.\n", "\n", "> 🎃 עובדה מעניינת, לפעמים אנחנו קוראים לדלעות לבנות 'דלעות רפאים'. הן לא קלות לגילוף, ולכן הן פחות פופולריות מהכתומות, אבל הן נראות מגניבות! אז אפשר גם לנסח מחדש את השאלה שלנו כ: 'רפאים' או 'לא רפאים'. 👻\n", "\n", "## **על רגרסיה לוגיסטית**\n", "\n", "רגרסיה לוגיסטית שונה מרגרסיה ליניארית, שלמדתם עליה קודם, בכמה דרכים חשובות.\n", "\n", "#### **סיווג בינארי**\n", "\n", "רגרסיה לוגיסטית אינה מציעה את אותן תכונות כמו רגרסיה ליניארית. הראשונה מציעה תחזית על `קטגוריה בינארית` (\"כתום או לא כתום\") בעוד שהאחרונה מסוגלת לחזות `ערכים רציפים`, לדוגמה, בהתחשב במקור הדלעת ובזמן הקטיף, *כמה המחיר שלה יעלה*.\n", "\n", "![אינפוגרפיקה מאת Dasani Madipalli](../../../../../../2-Regression/4-Logistic/images/pumpkin-classifier.png)\n", "\n", "### סיווגים אחרים\n", "\n", "ישנם סוגים נוספים של רגרסיה לוגיסטית, כולל מולטינומיאלית ואורדינלית:\n", "\n", "- **מולטינומיאלית**, שכוללת יותר מקטגוריה אחת - \"כתום, לבן ומפוספס\".\n", "\n", "- **אורדינלית**, שכוללת קטגוריות מסודרות, שימושית אם נרצה לסדר את התוצאות שלנו באופן לוגי, כמו הדלעות שלנו שמסודרות לפי מספר סופי של גדלים (מיני, קטן, בינוני, גדול, גדול מאוד, ענק).\n", "\n", "![רגרסיה מולטינומיאלית מול אורדינלית](../../../../../../2-Regression/4-Logistic/images/multinomial-vs-ordinal.png)\n", "\n", "#### **המשתנים לא חייבים להיות מתואמים**\n", "\n", "זוכרים איך רגרסיה ליניארית עבדה טוב יותר עם משתנים מתואמים? רגרסיה לוגיסטית היא ההפך - המשתנים לא חייבים להיות מתואמים. זה מתאים לנתונים שלנו שיש להם מתאמים חלשים יחסית.\n", "\n", "#### **צריך הרבה נתונים נקיים**\n", "\n", "רגרסיה לוגיסטית תיתן תוצאות מדויקות יותר אם תשתמשו ביותר נתונים; מאגר הנתונים הקטן שלנו אינו אופטימלי למשימה זו, אז קחו זאת בחשבון.\n", "\n", "✅ חשבו על סוגי הנתונים שיתאימו היטב לרגרסיה לוגיסטית\n", "\n", "## תרגיל - ניקוי הנתונים\n", "\n", "ראשית, נקו את הנתונים מעט, הסירו ערכים חסרים ובחרו רק חלק מהעמודות:\n", "\n", "1. הוסיפו את הקוד הבא:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Load the core tidyverse packages\n", "library(tidyverse)\n", "\n", "# Import the data and clean column names\n", "pumpkins <- read_csv(file = \"https://raw.githubusercontent.com/microsoft/ML-For-Beginners/main/2-Regression/data/US-pumpkins.csv\") %>% \n", " clean_names()\n", "\n", "# Select desired columns\n", "pumpkins_select <- pumpkins %>% \n", " select(c(city_name, package, variety, origin, item_size, color)) \n", "\n", "# Drop rows containing missing values and encode color as factor (category)\n", "pumpkins_select <- pumpkins_select %>% \n", " drop_na() %>% \n", " mutate(color = factor(color))\n", "\n", "# View the first few rows\n", "pumpkins_select %>% \n", " slice_head(n = 5)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "תמיד אפשר להציץ ב-DataFrame החדש שלך, באמצעות הפונקציה [*glimpse()*](https://pillar.r-lib.org/reference/glimpse.html) כפי שמוצג למטה:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "pumpkins_select %>% \n", " glimpse()\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "בואו נאשר שאנחנו באמת עומדים לבצע בעיית סיווג בינארית:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Subset distinct observations in outcome column\n", "pumpkins_select %>% \n", " distinct(color)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### ויזואליזציה - תרשים קטגורי\n", "עד עכשיו טענת שוב את נתוני הדלעת וניקית אותם כך שיישאר לך מאגר נתונים המכיל כמה משתנים, כולל צבע. בואו נבצע ויזואליזציה של מסגרת הנתונים במחברת באמצעות ספריית ggplot.\n", "\n", "ספריית ggplot מציעה דרכים נהדרות להמחיש את הנתונים שלך. לדוגמה, ניתן להשוות את התפלגויות הנתונים עבור כל זן וצבע בתרשים קטגורי.\n", "\n", "1. צור תרשים כזה באמצעות הפונקציה geombar, תוך שימוש בנתוני הדלעת שלנו, והגדרת מיפוי צבע עבור כל קטגוריית דלעת (כתום או לבן):\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "python" } }, "outputs": [], "source": [ "# Specify colors for each value of the hue variable\n", "palette <- c(ORANGE = \"orange\", WHITE = \"wheat\")\n", "\n", "# Create the bar plot\n", "ggplot(pumpkins_select, aes(y = variety, fill = color)) +\n", " geom_bar(position = \"dodge\") +\n", " scale_fill_manual(values = palette) +\n", " labs(y = \"Variety\", fill = \"Color\") +\n", " theme_minimal()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "על ידי התבוננות בנתונים, ניתן לראות כיצד נתוני הצבע קשורים לזן.\n", "\n", "✅ בהתבסס על התרשים הקטגורי הזה, אילו חקירות מעניינות ניתן לדמיין?\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### עיבוד נתונים: קידוד מאפיינים\n", "\n", "מערך הנתונים שלנו על דלעות מכיל ערכים מסוג מחרוזת בכל העמודות שלו. עבודה עם נתונים קטגוריים היא אינטואיטיבית עבור בני אדם, אך לא עבור מכונות. אלגוריתמים של למידת מכונה עובדים טוב עם מספרים. זו הסיבה שקידוד הוא שלב חשוב מאוד בשלב עיבוד הנתונים, מכיוון שהוא מאפשר לנו להפוך נתונים קטגוריים לנתונים מספריים, מבלי לאבד מידע. קידוד טוב מוביל לבניית מודל טוב.\n", "\n", "לקידוד מאפיינים יש שני סוגים עיקריים של מקודדים:\n", "\n", "1. מקודד סדרתי (Ordinal encoder): מתאים למשתנים סדרתיים, שהם משתנים קטגוריים שבהם הנתונים עוקבים אחר סדר לוגי, כמו עמודת `item_size` במערך הנתונים שלנו. הוא יוצר מיפוי כך שכל קטגוריה מיוצגת על ידי מספר, שהוא הסדר של הקטגוריה בעמודה.\n", "\n", "2. מקודד קטגוריאלי (Categorical encoder): מתאים למשתנים נומינליים, שהם משתנים קטגוריים שבהם הנתונים אינם עוקבים אחר סדר לוגי, כמו כל המאפיינים השונים מ-`item_size` במערך הנתונים שלנו. זהו קידוד מסוג one-hot, כלומר כל קטגוריה מיוצגת על ידי עמודה בינארית: המשתנה המקודד שווה ל-1 אם הדלעת שייכת לזן הזה ול-0 אחרת.\n", "\n", "Tidymodels מספקת חבילה נוספת ומועילה: [recipes](https://recipes.tidymodels.org/) - חבילה לעיבוד מקדים של נתונים. נגדיר `recipe` שמציין שכל עמודות המנבאים צריכות להיות מקודדות למערך של מספרים שלמים, נשתמש ב-`prep` כדי להעריך את הכמויות והסטטיסטיקות הנדרשות לכל פעולה, ולבסוף נשתמש ב-`bake` כדי ליישם את החישובים על נתונים חדשים.\n", "\n", "> בדרך כלל, recipes משמשת כמעבד מקדים למידול, שבו היא מגדירה אילו שלבים יש ליישם על מערך נתונים כדי להכין אותו למידול. במקרה כזה **מומלץ מאוד** להשתמש ב-`workflow()` במקום להעריך מתכון באופן ידני באמצעות prep ו-bake. נראה את כל זה בעוד רגע.\n", ">\n", "> עם זאת, כרגע אנו משתמשים ב-recipes + prep + bake כדי להגדיר אילו שלבים יש ליישם על מערך נתונים כדי להכין אותו לניתוח נתונים, ולאחר מכן לחלץ את הנתונים שעברו עיבוד עם השלבים שהוחלו.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Preprocess and extract data to allow some data analysis\n", "baked_pumpkins <- recipe(color ~ ., data = pumpkins_select) %>%\n", " # Define ordering for item_size column\n", " step_mutate(item_size = ordered(item_size, levels = c('sml', 'med', 'med-lge', 'lge', 'xlge', 'jbo', 'exjbo'))) %>%\n", " # Convert factors to numbers using the order defined above (Ordinal encoding)\n", " step_integer(item_size, zero_based = F) %>%\n", " # Encode all other predictors using one hot encoding\n", " step_dummy(all_nominal(), -all_outcomes(), one_hot = TRUE) %>%\n", " prep(data = pumpkin_select) %>%\n", " bake(new_data = NULL)\n", "\n", "# Display the first few rows of preprocessed data\n", "baked_pumpkins %>% \n", " slice_head(n = 5)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "✅ מהם היתרונות בשימוש ב-ordinal encoder עבור עמודת Item Size?\n", "\n", "### ניתוח קשרים בין משתנים\n", "\n", "כעת, לאחר שעיבדנו את הנתונים שלנו, נוכל לנתח את הקשרים בין המאפיינים לתווית כדי לקבל מושג עד כמה המודל יוכל לחזות את התווית בהתבסס על המאפיינים. הדרך הטובה ביותר לבצע ניתוח מסוג זה היא על ידי הצגת הנתונים בגרף. \n", "נשתמש שוב בפונקציה ggplot geom_boxplot_ כדי להמחיש את הקשרים בין Item Size, Variety ו-Color בגרף קטגורי. כדי להציג את הנתונים בצורה טובה יותר, נשתמש בעמודת Item Size המקודדת ובעמודת Variety הלא מקודדת.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Define the color palette\n", "palette <- c(ORANGE = \"orange\", WHITE = \"wheat\")\n", "\n", "# We need the encoded Item Size column to use it as the x-axis values in the plot\n", "pumpkins_select_plot<-pumpkins_select\n", "pumpkins_select_plot$item_size <- baked_pumpkins$item_size\n", "\n", "# Create the grouped box plot\n", "ggplot(pumpkins_select_plot, aes(x = `item_size`, y = color, fill = color)) +\n", " geom_boxplot() +\n", " facet_grid(variety ~ ., scales = \"free_x\") +\n", " scale_fill_manual(values = palette) +\n", " labs(x = \"Item Size\", y = \"\") +\n", " theme_minimal() +\n", " theme(strip.text = element_text(size = 12)) +\n", " theme(axis.text.x = element_text(size = 10)) +\n", " theme(axis.title.x = element_text(size = 12)) +\n", " theme(axis.title.y = element_blank()) +\n", " theme(legend.position = \"bottom\") +\n", " guides(fill = guide_legend(title = \"Color\")) +\n", " theme(panel.spacing = unit(0.5, \"lines\"))+\n", " theme(strip.text.y = element_text(size = 4, hjust = 0)) \n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### שימוש בגרף נחיל\n", "\n", "מכיוון ש-Color הוא קטגוריה בינארית (לבן או לא), יש צורך ב'[גישה מיוחדת](https://github.com/rstudio/cheatsheets/blob/main/data-visualization.pdf)' לצורך ויזואליזציה.\n", "\n", "נסו להשתמש ב`גרף נחיל` כדי להציג את התפלגות הצבע ביחס ל-item_size.\n", "\n", "נשתמש בחבילת [ggbeeswarm](https://github.com/eclarke/ggbeeswarm), שמספקת שיטות ליצירת גרפים בסגנון נחיל באמצעות ggplot2. גרפי נחיל הם דרך להציג נקודות שבדרך כלל היו חופפות, כך שהן מוצגות זו לצד זו במקום זאת.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Create beeswarm plots of color and item_size\n", "baked_pumpkins %>% \n", " mutate(color = factor(color)) %>% \n", " ggplot(mapping = aes(x = color, y = item_size, color = color)) +\n", " geom_quasirandom() +\n", " scale_color_brewer(palette = \"Dark2\", direction = -1) +\n", " theme(legend.position = \"none\")\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "עכשיו, כשיש לנו מושג על הקשר בין הקטגוריות הבינאריות של צבע לבין קבוצת הגדלים הרחבה יותר, בואו נחקור רגרסיה לוגיסטית כדי לקבוע את הצבע הסביר של דלעת נתונה.\n", "\n", "## בניית המודל שלך\n", "\n", "בחר את המשתנים שברצונך להשתמש בהם במודל הסיווג שלך וחלק את הנתונים לסטים של אימון ובדיקה. [rsample](https://rsample.tidymodels.org/), חבילה ב-Tidymodels, מספקת תשתית לחלוקה ולקיחת דגימות מחדש של נתונים בצורה יעילה:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Split data into 80% for training and 20% for testing\n", "set.seed(2056)\n", "pumpkins_split <- pumpkins_select %>% \n", " initial_split(prop = 0.8)\n", "\n", "# Extract the data in each split\n", "pumpkins_train <- training(pumpkins_split)\n", "pumpkins_test <- testing(pumpkins_split)\n", "\n", "# Print out the first 5 rows of the training set\n", "pumpkins_train %>% \n", " slice_head(n = 5)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "🙌 אנחנו מוכנים כעת לאמן מודל על ידי התאמת מאפייני האימון לתווית האימון (צבע).\n", "\n", "נתחיל ביצירת מתכון שמפרט את שלבי הקדם-עיבוד שצריך לבצע על הנתונים שלנו כדי להכין אותם למידול, כלומר: קידוד משתנים קטגוריים למספרים שלמים. בדיוק כמו `baked_pumpkins`, ניצור `pumpkins_recipe` אך לא נבצע `prep` ו-`bake`, מכיוון שזה ייכלל בתוך זרימת עבודה, כפי שתראו בעוד כמה שלבים.\n", "\n", "יש לא מעט דרכים להגדיר מודל רגרסיה לוגיסטית ב-Tidymodels. ראו `?logistic_reg()`. לעת עתה, נגדיר מודל רגרסיה לוגיסטית באמצעות מנוע ברירת המחדל `stats::glm()`.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Create a recipe that specifies preprocessing steps for modelling\n", "pumpkins_recipe <- recipe(color ~ ., data = pumpkins_train) %>% \n", " step_mutate(item_size = ordered(item_size, levels = c('sml', 'med', 'med-lge', 'lge', 'xlge', 'jbo', 'exjbo'))) %>%\n", " step_integer(item_size, zero_based = F) %>% \n", " step_dummy(all_nominal(), -all_outcomes(), one_hot = TRUE)\n", "\n", "# Create a logistic model specification\n", "log_reg <- logistic_reg() %>% \n", " set_engine(\"glm\") %>% \n", " set_mode(\"classification\")\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "עכשיו, כשיש לנו מתכון ומפרט מודל, אנחנו צריכים למצוא דרך לשלב אותם יחד בתוך אובייקט שיבצע תחילה עיבוד מקדים לנתונים (prep+bake מאחורי הקלעים), יתאים את המודל לנתונים שעברו עיבוד מקדים, וגם יאפשר פעילויות עיבוד לאחרי.\n", "\n", "ב-Tidymodels, האובייקט הנוח הזה נקרא [`workflow`](https://workflows.tidymodels.org/) והוא מחזיק בצורה נוחה את רכיבי המידול שלך.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Bundle modelling components in a workflow\n", "log_reg_wf <- workflow() %>% \n", " add_recipe(pumpkins_recipe) %>% \n", " add_model(log_reg)\n", "\n", "# Print out the workflow\n", "log_reg_wf\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "לאחר שזרימת עבודה *הוגדרה*, ניתן `לאמן` מודל באמצעות הפונקציה [`fit()`](https://tidymodels.github.io/parsnip/reference/fit.html). זרימת העבודה תעריך מתכון ותעבד את הנתונים לפני האימון, כך שלא נצטרך לעשות זאת באופן ידני באמצעות prep ו-bake.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Train the model\n", "wf_fit <- log_reg_wf %>% \n", " fit(data = pumpkins_train)\n", "\n", "# Print the trained workflow\n", "wf_fit\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "המודל מציג את המקדמים שנלמדו במהלך האימון.\n", "\n", "עכשיו, לאחר שאימנו את המודל באמצעות נתוני האימון, נוכל לבצע תחזיות על נתוני הבדיקה באמצעות [parsnip::predict()](https://parsnip.tidymodels.org/reference/predict.model_fit.html). נתחיל בשימוש במודל כדי לחזות תוויות עבור קבוצת הבדיקה שלנו ואת ההסתברויות עבור כל תווית. כאשר ההסתברות גבוהה מ-0.5, התווית החזויה היא `WHITE`, אחרת היא `ORANGE`.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Make predictions for color and corresponding probabilities\n", "results <- pumpkins_test %>% select(color) %>% \n", " bind_cols(wf_fit %>% \n", " predict(new_data = pumpkins_test)) %>%\n", " bind_cols(wf_fit %>%\n", " predict(new_data = pumpkins_test, type = \"prob\"))\n", "\n", "# Compare predictions\n", "results %>% \n", " slice_head(n = 10)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "ממש נחמד! זה מספק תובנות נוספות על איך רגרסיה לוגיסטית עובדת.\n", "\n", "### הבנה טובה יותר באמצעות מטריצת בלבול\n", "\n", "השוואת כל תחזית לערך האמיתי שלה (\"האמת הקרקעית\") אינה דרך יעילה במיוחד לקבוע עד כמה המודל מנבא בצורה טובה. למרבה המזל, ל-Tidymodels יש עוד כמה טריקים בשרוול: [`yardstick`](https://yardstick.tidymodels.org/) - חבילה המשמשת למדידת יעילות של מודלים באמצעות מדדי ביצועים.\n", "\n", "אחד ממדדי הביצועים הקשורים לבעיות סיווג הוא [`מטריצת בלבול`](https://wikipedia.org/wiki/Confusion_matrix). מטריצת בלבול מתארת עד כמה מודל סיווג מבצע את עבודתו. מטריצת בלבול מציגה כמה דוגמאות בכל קטגוריה סווגו בצורה נכונה על ידי המודל. במקרה שלנו, היא תראה לך כמה דלעות כתומות סווגו ככתומות וכמה דלעות לבנות סווגו כלבנות; מטריצת הבלבול גם תראה לך כמה סווגו לקטגוריות **שגויות**.\n", "\n", "הפונקציה [**`conf_mat()`**](https://tidymodels.github.io/yardstick/reference/conf_mat.html) מתוך yardstick מחשבת את הטבלה הזו של קטגוריות נצפות וקטגוריות מנובאות.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Confusion matrix for prediction results\n", "conf_mat(data = results, truth = color, estimate = .pred_class)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "בואו נפרש את מטריצת הבלבול. המודל שלנו מתבקש לסווג דלעות לשתי קטגוריות בינאריות, קטגוריה `לבן` וקטגוריה `לא-לבן`.\n", "\n", "- אם המודל שלכם מנבא שדלעת היא לבנה והיא באמת שייכת לקטגוריה 'לבן', אנו קוראים לזה `חיובי אמיתי`, שמוצג על ידי המספר בפינה השמאלית העליונה.\n", "\n", "- אם המודל שלכם מנבא שדלעת היא לא לבנה והיא באמת שייכת לקטגוריה 'לבן', אנו קוראים לזה `שלילי שגוי`, שמוצג על ידי המספר בפינה השמאלית התחתונה.\n", "\n", "- אם המודל שלכם מנבא שדלעת היא לבנה והיא באמת שייכת לקטגוריה 'לא-לבן', אנו קוראים לזה `חיובי שגוי`, שמוצג על ידי המספר בפינה הימנית העליונה.\n", "\n", "- אם המודל שלכם מנבא שדלעת היא לא לבנה והיא באמת שייכת לקטגוריה 'לא-לבן', אנו קוראים לזה `שלילי אמיתי`, שמוצג על ידי המספר בפינה הימנית התחתונה.\n", "\n", "| אמת |\n", "|:-----:|\n", "\n", "| | | |\n", "|---------------|--------|-------|\n", "| **ניבוי** | לבן | כתום |\n", "| לבן | TP | FP |\n", "| כתום | FN | TN |\n", "\n", "כפי שכנראה ניחשתם, עדיף שיהיה מספר גדול יותר של חיוביים אמיתיים ושליליים אמיתיים ומספר קטן יותר של חיוביים שגויים ושליליים שגויים, מה שמעיד על כך שהמודל מתפקד טוב יותר.\n", "\n", "מטריצת הבלבול מועילה מכיוון שהיא מובילה למדדים נוספים שיכולים לעזור לנו להעריך טוב יותר את ביצועי מודל הסיווג. בואו נעבור על כמה מהם:\n", "\n", "🎓 דיוק: `TP/(TP + FP)` מוגדר כחלק מהחיוביים שנחזו שהם באמת חיוביים. נקרא גם [ערך ניבוי חיובי](https://en.wikipedia.org/wiki/Positive_predictive_value \"Positive predictive value\").\n", "\n", "🎓 רגישות: `TP/(TP + FN)` מוגדרת כחלק מהתוצאות החיוביות מתוך מספר הדגימות שהיו באמת חיוביות. ידועה גם בשם `רגישות`.\n", "\n", "🎓 סגוליות: `TN/(TN + FP)` מוגדרת כחלק מהתוצאות השליליות מתוך מספר הדגימות שהיו באמת שליליות.\n", "\n", "🎓 דיוק כללי: `TP + TN/(TP + TN + FP + FN)` אחוז התוויות שנחזו בצורה מדויקת עבור דגימה.\n", "\n", "🎓 מדד F: ממוצע משוקלל של דיוק ורגישות, כאשר הטוב ביותר הוא 1 והגרוע ביותר הוא 0.\n", "\n", "בואו נחשב את המדדים האלה!\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Combine metric functions and calculate them all at once\n", "eval_metrics <- metric_set(ppv, recall, spec, f_meas, accuracy)\n", "eval_metrics(data = results, truth = color, estimate = .pred_class)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## הצגת עקומת ה-ROC של המודל הזה\n", "\n", "בואו נעשה ויזואליזציה נוספת כדי לראות את מה שנקרא [`עקומת ROC`](https://en.wikipedia.org/wiki/Receiver_operating_characteristic):\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Make a roc_curve\n", "results %>% \n", " roc_curve(color, .pred_ORANGE) %>% \n", " autoplot()\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "עקומות ROC משמשות לעיתים קרובות כדי לקבל מבט על הביצועים של מסווג במונחים של חיוביים אמיתיים לעומת חיוביים שגויים. עקומות ROC מציגות בדרך כלל את `True Positive Rate`/רגישות על ציר ה-Y, ואת `False Positive Rate`/1-ספציפיות על ציר ה-X. לכן, השיפוע של העקומה והמרחק בין קו האמצע לעקומה חשובים: המטרה היא עקומה שעולה במהירות ומתרחקת מקו האמצע. במקרה שלנו, ישנם חיוביים שגויים בהתחלה, ואז הקו עולה ומתרחק בצורה תקינה.\n", "\n", "לבסוף, נשתמש ב-`yardstick::roc_auc()` כדי לחשב את השטח מתחת לעקומה (AUC). אחת הדרכים לפרש את ה-AUC היא כהסתברות שהמודל מדרג דוגמה חיובית אקראית גבוה יותר מדוגמה שלילית אקראית.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "r" } }, "outputs": [], "source": [ "# Calculate area under curve\n", "results %>% \n", " roc_auc(color, .pred_ORANGE)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "התוצאה היא בערך `0.975`. מאחר ש-AUC נע בין 0 ל-1, אתם רוצים ציון גבוה, שכן מודל שמנבא בצורה מדויקת ב-100% יקבל AUC של 1; במקרה הזה, המודל הוא *די טוב*.\n", "\n", "בשיעורים הבאים על סיווגים, תלמדו כיצד לשפר את ציוני המודל שלכם (כמו למשל להתמודד עם נתונים לא מאוזנים במקרה הזה).\n", "\n", "## 🚀אתגר\n", "\n", "יש עוד הרבה מה ללמוד על רגרסיה לוגיסטית! אבל הדרך הטובה ביותר ללמוד היא להתנסות. מצאו מערך נתונים שמתאים לניתוח מסוג זה ובנו מודל בעזרתו. מה למדתם? טיפ: נסו את [Kaggle](https://www.kaggle.com/search?q=logistic+regression+datasets) למציאת מערכי נתונים מעניינים.\n", "\n", "## סקירה ולמידה עצמית\n", "\n", "קראו את העמודים הראשונים של [המאמר הזה מסטנפורד](https://web.stanford.edu/~jurafsky/slp3/5.pdf) על שימושים מעשיים ברגרסיה לוגיסטית. חשבו על משימות שמתאימות יותר לאחד מסוגי הרגרסיה שלמדנו עד כה. מה יעבוד הכי טוב?\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n---\n\n**כתב ויתור**: \nמסמך זה תורגם באמצעות שירות תרגום מבוסס בינה מלאכותית [Co-op Translator](https://github.com/Azure/co-op-translator). למרות שאנו שואפים לדיוק, יש לקחת בחשבון שתרגומים אוטומטיים עשויים להכיל שגיאות או אי דיוקים. המסמך המקורי בשפתו המקורית צריך להיחשב כמקור סמכותי. עבור מידע קריטי, מומלץ להשתמש בתרגום מקצועי על ידי אדם. איננו נושאים באחריות לאי הבנות או לפרשנויות שגויות הנובעות משימוש בתרגום זה.\n" ] } ], "metadata": { "anaconda-cloud": "", "kernelspec": { "display_name": "R", "langauge": "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" }, "coopTranslator": { "original_hash": "feaf125f481a89c468fa115bf2aed580", "translation_date": "2025-09-04T06:53:57+00:00", "source_file": "2-Regression/4-Logistic/solution/R/lesson_4-R.ipynb", "language_code": "he" } }, "nbformat": 4, "nbformat_minor": 1 }