{ "nbformat": 4, "nbformat_minor": 2, "metadata": { "colab": { "name": "lesson_3-R.ipynb", "provenance": [], "collapsed_sections": [], "toc_visible": true }, "kernelspec": { "name": "ir", "display_name": "R" }, "language_info": { "name": "R" }, "coopTranslator": { "original_hash": "5015d65d61ba75a223bfc56c273aa174", "translation_date": "2025-09-04T06:34:07+00:00", "source_file": "2-Regression/3-Linear/solution/R/lesson_3-R.ipynb", "language_code": "he" } }, "cells": [ { "cell_type": "markdown", "source": [ "# בנה מודל רגרסיה: מודלים של רגרסיה לינארית ופולינומית\n" ], "metadata": { "id": "EgQw8osnsUV-" } }, { "cell_type": "markdown", "source": [ "## רגרסיה ליניארית ופולינומית לתמחור דלעות - שיעור 3\n", "

\n", " \n", "

אינפוגרפיקה מאת דאסאני מדיפאלי
\n", "\n", "#### הקדמה\n", "\n", "עד כה חקרתם מהי רגרסיה באמצעות נתוני דוגמה שנאספו ממאגר הנתונים של תמחור דלעות שבו נשתמש לאורך השיעור הזה. בנוסף, גם ביצעתם ויזואליזציה של הנתונים באמצעות `ggplot2`. 💪\n", "\n", "עכשיו אתם מוכנים לצלול עמוק יותר לתוך עולם הרגרסיה עבור למידת מכונה. בשיעור הזה תלמדו יותר על שני סוגי רגרסיה: *רגרסיה ליניארית בסיסית* ו-*רגרסיה פולינומית*, יחד עם חלק מהמתמטיקה שמאחורי הטכניקות הללו.\n", "\n", "> לאורך הקורס הזה, אנו מניחים ידע מתמטי מינימלי ושואפים להפוך את החומר לנגיש עבור תלמידים שמגיעים מתחומים אחרים. שימו לב להערות, 🧮 קריאות, דיאגרמות וכלים נוספים שיעזרו בהבנה.\n", "\n", "#### הכנה\n", "\n", "כתזכורת, אתם טוענים את הנתונים הללו כדי לשאול שאלות לגביהם.\n", "\n", "- מתי הזמן הטוב ביותר לקנות דלעות?\n", "\n", "- איזה מחיר אני יכול לצפות עבור ארגז של דלעות מיניאטוריות?\n", "\n", "- האם כדאי לי לקנות אותן בסלים של חצי בושל או בארגזים של 1 1/9 בושל? בואו נמשיך לחקור את הנתונים הללו.\n", "\n", "בשיעור הקודם יצרתם `tibble` (גרסה מודרנית של מסגרת נתונים) ומילאתם אותו עם חלק ממאגר הנתונים המקורי, תוך סטנדרטיזציה של התמחור לפי בושל. עם זאת, על ידי כך הצלחתם לאסוף רק כ-400 נקודות נתונים ורק עבור חודשי הסתיו. אולי נוכל לקבל קצת יותר פרטים על טיב הנתונים על ידי ניקוי נוסף שלהם? נראה... 🕵️‍♀️\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", "- `corrplot`: [חבילת corrplot](https://cran.r-project.org/web/packages/corrplot/vignettes/corrplot-intro.html) מספקת כלי ויזואלי לחקר מטריצת מתאם, שתומך בסידור אוטומטי של משתנים כדי לעזור לזהות דפוסים נסתרים בין משתנים.\n", "\n", "ניתן להתקין את החבילות הללו באמצעות:\n", "\n", "`install.packages(c(\"tidyverse\", \"tidymodels\", \"janitor\", \"corrplot\"))`\n", "\n", "הסקריפט הבא בודק אם יש לכם את החבילות הנדרשות להשלמת המודול הזה ומתקין אותן עבורכם במקרה שהן חסרות.\n" ], "metadata": { "id": "WqQPS1OAsg3H" } }, { "cell_type": "code", "execution_count": null, "source": [ "suppressWarnings(if (!require(\"pacman\")) install.packages(\"pacman\"))\n", "\n", "pacman::p_load(tidyverse, tidymodels, janitor, corrplot)" ], "outputs": [], "metadata": { "id": "tA4C2WN3skCf", "colab": { "base_uri": "https://localhost:8080/" }, "outputId": "c06cd805-5534-4edc-f72b-d0d1dab96ac0" } }, { "cell_type": "markdown", "source": [ "בהמשך נטען את החבילות המדהימות הללו ונעשה אותן זמינות בסשן הנוכחי של R שלנו. (זה רק להמחשה, `pacman::p_load()` כבר עשה זאת בשבילכם)\n", "\n", "## 1. קו רגרסיה ליניארי\n", "\n", "כפי שלמדתם בשיעור 1, המטרה של תרגיל רגרסיה ליניארית היא להיות מסוגלים לשרטט *קו* *התאמה* *הטוב ביותר* כדי:\n", "\n", "- **להציג קשרים בין משתנים**. להראות את הקשר בין המשתנים.\n", "\n", "- **לבצע תחזיות**. לבצע תחזיות מדויקות לגבי היכן נקודת נתונים חדשה תיפול ביחס לקו הזה.\n", "\n", "כדי לשרטט סוג כזה של קו, אנו משתמשים בטכניקה סטטיסטית שנקראת **רגרסיית ריבועים קטנים**. המונח `ריבועים קטנים` מתייחס לכך שכל נקודות הנתונים שמסביב לקו הרגרסיה מרובעות ואז מסוכמות. באופן אידיאלי, הסכום הסופי יהיה קטן ככל האפשר, מכיוון שאנו רוצים מספר נמוך של שגיאות, או `ריבועים קטנים`. לכן, קו ההתאמה הטוב ביותר הוא הקו שנותן לנו את הערך הנמוך ביותר עבור סכום השגיאות המרובעות - ומכאן השם *רגרסיית ריבועים קטנים*.\n", "\n", "אנו עושים זאת מכיוון שאנו רוצים לדגם קו שיש לו את המרחק המצטבר הקטן ביותר מכל נקודות הנתונים שלנו. אנו גם מרבעים את המונחים לפני הסכימה מכיוון שאנו מתמקדים בגודל שלהם ולא בכיוונם.\n", "\n", "> **🧮 תראו לי את המתמטיקה**\n", ">\n", "> קו זה, שנקרא *קו ההתאמה הטוב ביותר*, ניתן לביטוי באמצעות [משוואה](https://en.wikipedia.org/wiki/Simple_linear_regression):\n", ">\n", "> Y = a + bX\n", ">\n", "> `X` הוא '`משתנה מסביר` או `מנבא`'. `Y` הוא '`משתנה תלוי` או `תוצאה`'. השיפוע של הקו הוא `b` ו-`a` הוא נקודת החיתוך עם ציר ה-Y, שמתייחסת לערך של `Y` כאשר `X = 0`.\n", ">\n", "\n", "> ![](../../../../../../2-Regression/3-Linear/solution/images/slope.png \"שיפוע = $y/x$\")\n", " אינפוגרפיקה מאת ג'ן לופר\n", ">\n", "> ראשית, חשבו את השיפוע `b`.\n", ">\n", "> במילים אחרות, ובהתייחס לשאלת הנתונים המקורית שלנו על דלעות: \"לחזות את המחיר של דלעת לפי חודש\", `X` יתייחס למחיר ו-`Y` יתייחס לחודש המכירה.\n", ">\n", "> ![](../../../../../../2-Regression/3-Linear/solution/images/calculation.png)\n", " אינפוגרפיקה מאת ג'ן לופר\n", "> \n", "> חשבו את הערך של Y. אם אתם משלמים בסביבות \\$4, כנראה שזה אפריל!\n", ">\n", "> המתמטיקה שמחשבת את הקו חייבת להדגים את השיפוע של הקו, שהוא גם תלוי בנקודת החיתוך, או היכן ש-`Y` ממוקם כאשר `X = 0`.\n", ">\n", "> אתם יכולים לצפות בשיטת החישוב לערכים אלו באתר [Math is Fun](https://www.mathsisfun.com/data/least-squares-regression.html). כמו כן, בקרו ב-[מחשבון ריבועים קטנים](https://www.mathsisfun.com/data/least-squares-calculator.html) כדי לראות כיצד ערכי המספרים משפיעים על הקו.\n", "\n", "לא כל כך מפחיד, נכון? 🤓\n", "\n", "#### מתאם\n", "\n", "מונח נוסף שחשוב להבין הוא **מקדם המתאם** בין משתני X ו-Y נתונים. באמצעות תרשים פיזור, ניתן לראות במהירות את מקדם המתאם הזה. תרשים עם נקודות נתונים מפוזרות בקו מסודר מצביע על מתאם גבוה, אך תרשים עם נקודות נתונים מפוזרות בכל מקום בין X ל-Y מצביע על מתאם נמוך.\n", "\n", "מודל רגרסיה ליניארי טוב יהיה כזה שיש לו מקדם מתאם גבוה (קרוב ל-1 יותר מאשר ל-0) באמצעות שיטת רגרסיית ריבועים קטנים עם קו רגרסיה.\n" ], "metadata": { "id": "cdX5FRpvsoP5" } }, { "cell_type": "markdown", "source": [ "## **2. ריקוד עם נתונים: יצירת מסגרת נתונים לשימוש במידול**\n", "\n", "

\n", " \n", "

יצירה מאת @allison_horst
\n", "\n", "\n", "\n" ], "metadata": { "id": "WdUKXk7Bs8-V" } }, { "cell_type": "markdown", "source": [ "טען את הספריות והמערכת הנתונים הנדרשות. המרה של הנתונים למסגרת נתונים המכילה תת-קבוצה של הנתונים:\n", "\n", "- קבל רק דלעות שמחירן נקבע לפי יחידת מדידה של \"בושל\"\n", "\n", "- המרה של התאריך לחודש\n", "\n", "- חישוב המחיר כממוצע של המחירים הגבוהים והנמוכים\n", "\n", "- המרה של המחיר כך שישקף את התמחור לפי כמות בושל\n", "\n", "> כיסינו את השלבים הללו ב[שיעור הקודם](https://github.com/microsoft/ML-For-Beginners/blob/main/2-Regression/2-Data/solution/lesson_2-R.ipynb).\n" ], "metadata": { "id": "fMCtu2G2s-p8" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Load the core Tidyverse packages\n", "library(tidyverse)\n", "library(lubridate)\n", "\n", "# Import the pumpkins data\n", "pumpkins <- read_csv(file = \"https://raw.githubusercontent.com/microsoft/ML-For-Beginners/main/2-Regression/data/US-pumpkins.csv\")\n", "\n", "\n", "# Get a glimpse and dimensions of the data\n", "glimpse(pumpkins)\n", "\n", "\n", "# Print the first 50 rows of the data set\n", "pumpkins %>% \n", " slice_head(n = 5)" ], "outputs": [], "metadata": { "id": "ryMVZEEPtERn" } }, { "cell_type": "markdown", "source": [ "ברוח ההרפתקה הטהורה, בואו נחקור את [`חבילת השרת`](../../../../../../2-Regression/3-Linear/solution/R/github.com/sfirke/janitor) שמספקת פונקציות פשוטות לבחינה וניקוי נתונים מלוכלכים. לדוגמה, בואו נסתכל על שמות העמודות של הנתונים שלנו:\n" ], "metadata": { "id": "xcNxM70EtJjb" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Return column names\n", "pumpkins %>% \n", " names()" ], "outputs": [], "metadata": { "id": "5XtpaIigtPfW" } }, { "cell_type": "markdown", "source": [ "🤔 אנחנו יכולים לעשות טוב יותר. בואו נהפוך את שמות העמודות ל-`friendR` על ידי המרתם לתקן [snake_case](https://en.wikipedia.org/wiki/Snake_case) באמצעות `janitor::clean_names`. כדי לגלות עוד על הפונקציה הזו: `?clean_names`\n" ], "metadata": { "id": "IbIqrMINtSHe" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Clean names to the snake_case convention\n", "pumpkins <- pumpkins %>% \n", " clean_names(case = \"snake\")\n", "\n", "# Return column names\n", "pumpkins %>% \n", " names()" ], "outputs": [], "metadata": { "id": "a2uYvclYtWvX" } }, { "cell_type": "markdown", "source": [ "הרבה tidyR 🧹! עכשיו, ריקוד עם הנתונים באמצעות `dplyr` כמו בשיעור הקודם! 💃\n" ], "metadata": { "id": "HfhnuzDDtaDd" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Select desired columns\n", "pumpkins <- pumpkins %>% \n", " select(variety, city_name, package, low_price, high_price, date)\n", "\n", "\n", "\n", "# Extract the month from the dates to a new column\n", "pumpkins <- pumpkins %>%\n", " mutate(date = mdy(date),\n", " month = month(date)) %>% \n", " select(-date)\n", "\n", "\n", "\n", "# Create a new column for average Price\n", "pumpkins <- pumpkins %>% \n", " mutate(price = (low_price + high_price)/2)\n", "\n", "\n", "# Retain only pumpkins with the string \"bushel\"\n", "new_pumpkins <- pumpkins %>% \n", " filter(str_detect(string = package, pattern = \"bushel\"))\n", "\n", "\n", "# Normalize the pricing so that you show the pricing per bushel, not per 1 1/9 or 1/2 bushel\n", "new_pumpkins <- new_pumpkins %>% \n", " mutate(price = case_when(\n", " str_detect(package, \"1 1/9\") ~ price/(1.1),\n", " str_detect(package, \"1/2\") ~ price*2,\n", " TRUE ~ price))\n", "\n", "# Relocate column positions\n", "new_pumpkins <- new_pumpkins %>% \n", " relocate(month, .before = variety)\n", "\n", "\n", "# Display the first 5 rows\n", "new_pumpkins %>% \n", " slice_head(n = 5)" ], "outputs": [], "metadata": { "id": "X0wU3gQvtd9f" } }, { "cell_type": "markdown", "source": [ "עבודה טובה!👌 עכשיו יש לך מערך נתונים נקי ומסודר שעליו תוכל לבנות את מודל הרגרסיה החדש שלך!\n", "\n", "מה דעתך על גרף פיזור?\n" ], "metadata": { "id": "UpaIwaxqth82" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Set theme\n", "theme_set(theme_light())\n", "\n", "# Make a scatter plot of month and price\n", "new_pumpkins %>% \n", " ggplot(mapping = aes(x = month, y = price)) +\n", " geom_point(size = 1.6)\n" ], "outputs": [], "metadata": { "id": "DXgU-j37tl5K" } }, { "cell_type": "markdown", "source": [ "פיזור הנתונים מזכיר לנו שיש לנו נתוני חודשים רק מאוגוסט ועד דצמבר. כנראה שנצטרך יותר נתונים כדי שנוכל להסיק מסקנות בצורה ליניארית.\n", "\n", "בואו נבחן שוב את נתוני המודל שלנו:\n" ], "metadata": { "id": "Ve64wVbwtobI" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Display first 5 rows\n", "new_pumpkins %>% \n", " slice_head(n = 5)" ], "outputs": [], "metadata": { "id": "HFQX2ng1tuSJ" } }, { "cell_type": "markdown", "source": [ "מה אם היינו רוצים לחזות את `price` של דלעת בהתבסס על העמודות `city` או `package`, שהן מסוג טקסט? או אפילו בצורה פשוטה יותר, איך נוכל למצוא את הקורלציה (שדורשת ששני הקלטים שלה יהיו מספריים) בין, למשל, `package` ו-`price`? 🤷🤷\n", "\n", "מודלים של למידת מכונה עובדים בצורה הטובה ביותר עם מאפיינים מספריים ולא עם ערכי טקסט, ולכן בדרך כלל יש צורך להמיר מאפיינים קטגוריים לייצוגים מספריים.\n", "\n", "זה אומר שעלינו למצוא דרך לעצב מחדש את המנבאים שלנו כדי להפוך אותם לקלים יותר לשימוש עבור מודל, תהליך שמכונה `feature engineering`.\n" ], "metadata": { "id": "7hsHoxsStyjJ" } }, { "cell_type": "markdown", "source": [ "## 3. עיבוד מקדים של נתונים למידול עם מתכונים 👩‍🍳👨‍🍳\n", "\n", "פעילויות שמעצבות מחדש ערכי מנבאים כדי להפוך אותם לקלים יותר לשימוש עבור מודל נקראות `הנדסת מאפיינים`.\n", "\n", "למודלים שונים יש דרישות עיבוד מקדים שונות. לדוגמה, ריבועי מינימום דורשים `קידוד משתנים קטגוריים` כמו חודש, סוג ועיר. זה פשוט כרוך ב`תרגום` עמודה עם `ערכים קטגוריים` לעמודה אחת או יותר `מספריות` שמחליפות את המקור.\n", "\n", "לדוגמה, נניח שהנתונים שלך כוללים את המאפיין הקטגורי הבא:\n", "\n", "| עיר |\n", "|:-------:|\n", "| דנוור |\n", "| ניירובי |\n", "| טוקיו |\n", "\n", "ניתן ליישם *קידוד סדרתי* כדי להחליף כל קטגוריה בערך מספרי ייחודי, כך:\n", "\n", "| עיר |\n", "|:----:|\n", "| 0 |\n", "| 1 |\n", "| 2 |\n", "\n", "וזה בדיוק מה שנעשה לנתונים שלנו!\n", "\n", "בקטע הזה, נחקור חבילה מדהימה נוספת של Tidymodels: [recipes](https://tidymodels.github.io/recipes/) - שנועדה לעזור לך לעבד את הנתונים שלך **לפני** אימון המודל. בליבה, מתכון הוא אובייקט שמגדיר אילו שלבים יש ליישם על מערך נתונים כדי להכין אותו למידול.\n", "\n", "עכשיו, בואו ניצור מתכון שמכין את הנתונים שלנו למידול על ידי החלפת מספר ייחודי לכל התצפיות בעמודות המנבאים:\n" ], "metadata": { "id": "AD5kQbcvt3Xl" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Specify a recipe\n", "pumpkins_recipe <- recipe(price ~ ., data = new_pumpkins) %>% \n", " step_integer(all_predictors(), zero_based = TRUE)\n", "\n", "\n", "# Print out the recipe\n", "pumpkins_recipe" ], "outputs": [], "metadata": { "id": "BNaFKXfRt9TU" } }, { "cell_type": "markdown", "source": [ "איזה כיף! 👏 הרגע יצרנו את המתכון הראשון שלנו שמגדיר תוצאה (מחיר) ואת המשתנים המנבאים שלה, וכל עמודות המנבאים צריכות להיות מקודדות למספרים שלמים 🙌! בואו נפרק את זה במהירות:\n", "\n", "- הקריאה ל-`recipe()` עם נוסחה אומרת למתכון את *התפקידים* של המשתנים תוך שימוש בנתוני `new_pumpkins` כנקודת ייחוס. לדוגמה, לעמודת `price` הוקצה תפקיד של `outcome`, בעוד שלשאר העמודות הוקצה תפקיד של `predictor`.\n", "\n", "- `step_integer(all_predictors(), zero_based = TRUE)` מציין שכל המנבאים צריכים להיות מומרות למספרים שלמים עם מספור שמתחיל מ-0.\n", "\n", "אנחנו בטוחים שיש לכם מחשבות כמו: \"זה כל כך מגניב!! אבל מה אם אני צריך לוודא שהמתכונים עושים בדיוק את מה שאני מצפה מהם? 🤔\"\n", "\n", "זו מחשבה מעולה! תראו, ברגע שהמתכון שלכם מוגדר, אתם יכולים להעריך את הפרמטרים הנדרשים כדי לעבד את הנתונים בפועל, ואז לחלץ את הנתונים המעובדים. בדרך כלל אין צורך לעשות זאת כשמשתמשים ב-Tidymodels (נראה את השיטה המקובלת בעוד רגע-\\> `workflows`), אבל זה יכול להיות שימושי כשאתם רוצים לבצע בדיקת תקינות כדי לוודא שהמתכונים עושים את מה שאתם מצפים.\n", "\n", "לשם כך, תצטרכו שני פעלים נוספים: `prep()` ו-`bake()`, וכרגיל, חברינו הקטנים מ-R מאת [`Allison Horst`](https://github.com/allisonhorst/stats-illustrations) עוזרים לכם להבין את זה טוב יותר!\n", "\n", "

\n", " \n", "

יצירה מאת @allison_horst
\n" ], "metadata": { "id": "KEiO0v7kuC9O" } }, { "cell_type": "markdown", "source": [ "[`prep()`](https://recipes.tidymodels.org/reference/prep.html): מעריך את הפרמטרים הנדרשים מתוך קבוצת אימון, שניתן ליישם מאוחר יותר על מערכי נתונים אחרים. לדוגמה, עבור עמודת מנבא מסוימת, איזו תצפית תוקצה למספר שלם 0 או 1 או 2 וכו'.\n", "\n", "[`bake()`](https://recipes.tidymodels.org/reference/bake.html): לוקח מתכון שעבר הכנה ומבצע את הפעולות על כל מערך נתונים.\n", "\n", "עם זאת, בואו נכין ונאפה את המתכונים שלנו כדי לאשר באמת שמתחת לפני השטח, עמודות המנבא יעברו קידוד תחילה לפני התאמת המודל.\n" ], "metadata": { "id": "Q1xtzebuuTCP" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Prep the recipe\n", "pumpkins_prep <- prep(pumpkins_recipe)\n", "\n", "# Bake the recipe to extract a preprocessed new_pumpkins data\n", "baked_pumpkins <- bake(pumpkins_prep, new_data = NULL)\n", "\n", "# Print out the baked data set\n", "baked_pumpkins %>% \n", " slice_head(n = 10)" ], "outputs": [], "metadata": { "id": "FGBbJbP_uUUn" } }, { "cell_type": "markdown", "source": [ "יש! 🥳 הנתונים המעובדים `baked_pumpkins` כוללים את כל המשתנים המקודדים, מה שמאשר שהשלבים המקדימים שהגדרנו כמתכון אכן עובדים כמצופה. זה אולי מקשה עליך לקרוא את הנתונים, אבל הופך אותם להרבה יותר מובנים עבור Tidymodels! הקדש זמן לבדוק איזו תצפית הותאמה למספר שלם מתאים.\n", "\n", "כדאי גם לציין ש-`baked_pumpkins` הוא מסגרת נתונים (data frame) שניתן לבצע עליה חישובים.\n", "\n", "לדוגמה, בואו ננסה למצוא מתאם טוב בין שתי נקודות בנתונים שלך כדי לבנות מודל חיזוי איכותי. נשתמש בפונקציה `cor()` כדי לעשות זאת. הקלד `?cor()` כדי ללמוד עוד על הפונקציה.\n" ], "metadata": { "id": "1dvP0LBUueAW" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Find the correlation between the city_name and the price\n", "cor(baked_pumpkins$city_name, baked_pumpkins$price)\n", "\n", "# Find the correlation between the package and the price\n", "cor(baked_pumpkins$package, baked_pumpkins$price)\n" ], "outputs": [], "metadata": { "id": "3bQzXCjFuiSV" } }, { "cell_type": "markdown", "source": [ "כפי שמתברר, יש רק קשר חלש בין העיר למחיר. עם זאת, יש קשר קצת יותר טוב בין החבילה למחיר שלה. זה הגיוני, נכון? בדרך כלל, ככל שארגז המוצרים גדול יותר, המחיר גבוה יותר.\n", "\n", "בזמן שאנחנו עוסקים בזה, בואו גם ננסה להמחיש מטריצת מתאמים של כל העמודות באמצעות חבילת `corrplot`.\n" ], "metadata": { "id": "BToPWbgjuoZw" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Load the corrplot package\n", "library(corrplot)\n", "\n", "# Obtain correlation matrix\n", "corr_mat <- cor(baked_pumpkins %>% \n", " # Drop columns that are not really informative\n", " select(-c(low_price, high_price)))\n", "\n", "# Make a correlation plot between the variables\n", "corrplot(corr_mat, method = \"shade\", shade.col = NA, tl.col = \"black\", tl.srt = 45, addCoef.col = \"black\", cl.pos = \"n\", order = \"original\")" ], "outputs": [], "metadata": { "id": "ZwAL3ksmutVR" } }, { "cell_type": "markdown", "source": [ "🤩🤩 הרבה יותר טוב.\n", "\n", "שאלה טובה לשאול עכשיו מהנתונים היא: '`איזה מחיר אני יכול לצפות עבור חבילת דלעת מסוימת?`' בואו נצלול ישר לתוך זה!\n", "\n", "> הערה: כאשר אתם **`bake()`** את המתכון המוכן **`pumpkins_prep`** עם **`new_data = NULL`**, אתם מחלצים את נתוני האימון המעובדים (כלומר, מקודדים). אם היה לכם סט נתונים נוסף, לדוגמה סט בדיקה, ורציתם לראות איך המתכון יעבד אותו, פשוט תאפו את **`pumpkins_prep`** עם **`new_data = test_set`**\n", "\n", "## 4. בניית מודל רגרסיה ליניארית\n", "\n", "

\n", " \n", "

אינפוגרפיקה מאת דאסאני מדיפאלי
\n" ], "metadata": { "id": "YqXjLuWavNxW" } }, { "cell_type": "markdown", "source": [ "עכשיו, לאחר שבנינו מתכון ואישרנו שהנתונים יעובדו מראש בצורה המתאימה, בואו נבנה מודל רגרסיה כדי לענות על השאלה: `איזה מחיר אני יכול לצפות עבור חבילת דלעת נתונה?`\n", "\n", "#### אימון מודל רגרסיה לינארית באמצעות קבוצת האימון\n", "\n", "כפי שכנראה כבר הבנתם, העמודה *price* היא משתנה ה`תוצאה`, בעוד שהעמודה *package* היא משתנה ה`מנבא`.\n", "\n", "כדי לעשות זאת, תחילה נחלק את הנתונים כך ש-80% ייכנסו לקבוצת האימון ו-20% לקבוצת הבדיקה, לאחר מכן נגדיר מתכון שיקודד את עמודת המנבא למערך של מספרים שלמים, ואז נבנה מפרט מודל. לא נכין ונאפה את המתכון שלנו מכיוון שכבר ידוע לנו שהוא יעבד את הנתונים כפי שצפוי.\n" ], "metadata": { "id": "Pq0bSzCevW-h" } }, { "cell_type": "code", "execution_count": null, "source": [ "set.seed(2056)\n", "# Split the data into training and test sets\n", "pumpkins_split <- new_pumpkins %>% \n", " initial_split(prop = 0.8)\n", "\n", "\n", "# Extract training and test data\n", "pumpkins_train <- training(pumpkins_split)\n", "pumpkins_test <- testing(pumpkins_split)\n", "\n", "\n", "\n", "# Create a recipe for preprocessing the data\n", "lm_pumpkins_recipe <- recipe(price ~ package, data = pumpkins_train) %>% \n", " step_integer(all_predictors(), zero_based = TRUE)\n", "\n", "\n", "\n", "# Create a linear model specification\n", "lm_spec <- linear_reg() %>% \n", " set_engine(\"lm\") %>% \n", " set_mode(\"regression\")" ], "outputs": [], "metadata": { "id": "CyoEh_wuvcLv" } }, { "cell_type": "markdown", "source": [ "עבודה טובה! עכשיו כשיש לנו מתכון ומפרט מודל, אנחנו צריכים למצוא דרך לאגד אותם יחד לאובייקט שיבצע תחילה עיבוד מקדים לנתונים (prep+bake מאחורי הקלעים), יתאים את המודל לנתונים שעברו עיבוד מקדים וגם יאפשר פעילויות עיבוד לאחרי. איך זה בשביל השקט הנפשי שלך!🤩\n", "\n", "ב-Tidymodels, האובייקט הנוח הזה נקרא [`workflow`](https://workflows.tidymodels.org/) והוא מחזיק בצורה נוחה את רכיבי המידול שלך! זה מה שהיינו קוראים לו *pipelines* ב-*Python*.\n", "\n", "אז בואו נאגד הכל לתוך workflow!📦\n" ], "metadata": { "id": "G3zF_3DqviFJ" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Hold modelling components in a workflow\n", "lm_wf <- workflow() %>% \n", " add_recipe(lm_pumpkins_recipe) %>% \n", " add_model(lm_spec)\n", "\n", "# Print out the workflow\n", "lm_wf" ], "outputs": [], "metadata": { "id": "T3olroU3v-WX" } }, { "cell_type": "markdown", "source": [ "בנוסף לכך, ניתן להתאים/לאמן תהליך עבודה בצורה דומה מאוד לאופן שבו ניתן לאמן מודל.\n" ], "metadata": { "id": "zd1A5tgOwEPX" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Train the model\n", "lm_wf_fit <- lm_wf %>% \n", " fit(data = pumpkins_train)\n", "\n", "# Print the model coefficients learned \n", "lm_wf_fit" ], "outputs": [], "metadata": { "id": "NhJagFumwFHf" } }, { "cell_type": "markdown", "source": [ "מהפלט של המודל, ניתן לראות את המקדמים שנלמדו במהלך האימון. הם מייצגים את המקדמים של קו ההתאמה הטוב ביותר שמספק את השגיאה הכוללת הנמוכה ביותר בין המשתנה האמיתי למשתנה החזוי.\n", "\n", "#### הערכת ביצועי המודל באמצעות קבוצת הבדיקה\n", "\n", "הגיע הזמן לבדוק איך המודל ביצע 📏! איך עושים את זה?\n", "\n", "עכשיו, לאחר שאימנו את המודל, נוכל להשתמש בו כדי לבצע תחזיות עבור קבוצת הבדיקה באמצעות `parsnip::predict()`. לאחר מכן, נוכל להשוות את התחזיות הללו לערכי התוויות האמיתיים כדי להעריך עד כמה (או לא!) המודל עובד.\n", "\n", "בואו נתחיל עם ביצוע תחזיות עבור קבוצת הבדיקה ואז נחבר את העמודות לקבוצת הבדיקה.\n" ], "metadata": { "id": "_4QkGtBTwItF" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Make predictions for the test set\n", "predictions <- lm_wf_fit %>% \n", " predict(new_data = pumpkins_test)\n", "\n", "\n", "# Bind predictions to the test set\n", "lm_results <- pumpkins_test %>% \n", " select(c(package, price)) %>% \n", " bind_cols(predictions)\n", "\n", "\n", "# Print the first ten rows of the tibble\n", "lm_results %>% \n", " slice_head(n = 10)" ], "outputs": [], "metadata": { "id": "UFZzTG0gwTs9" } }, { "cell_type": "markdown", "source": [ "כן, הרגע אימנתם מודל והשתמשתם בו כדי לבצע תחזיות!🔮 האם הוא טוב? בואו נבחן את ביצועי המודל!\n", "\n", "ב-Tidymodels, אנחנו עושים זאת באמצעות `yardstick::metrics()`! עבור רגרסיה לינארית, נתמקד במדדים הבאים:\n", "\n", "- `Root Mean Square Error (RMSE)`: השורש הריבועי של [MSE](https://en.wikipedia.org/wiki/Mean_squared_error). מדד זה מספק ערך מוחלט באותה יחידת מידה כמו התווית (במקרה הזה, המחיר של דלעת). ככל שהערך קטן יותר, כך המודל טוב יותר (במובן הפשוט, זה מייצג את המחיר הממוצע שבו התחזיות שגויות!).\n", "\n", "- `Coefficient of Determination (בדרך כלל נקרא R-squared או R2)`: מדד יחסי שבו ככל שהערך גבוה יותר, כך ההתאמה של המודל טובה יותר. למעשה, מדד זה מייצג כמה מהשונות בין הערכים החזויים לערכים האמיתיים המודל מצליח להסביר.\n" ], "metadata": { "id": "0A5MjzM7wW9M" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Evaluate performance of linear regression\n", "metrics(data = lm_results,\n", " truth = price,\n", " estimate = .pred)" ], "outputs": [], "metadata": { "id": "reJ0UIhQwcEH" } }, { "cell_type": "markdown", "source": [ "הנה ביצועי המודל. בואו נראה אם נוכל לקבל אינדיקציה טובה יותר על ידי הצגת גרף פיזור של החבילה והמחיר, ואז להשתמש בתחזיות שנעשו כדי להוסיף קו מגמה מתאים.\n", "\n", "זה אומר שנצטרך להכין ולעבד את קבוצת הבדיקה כדי לקודד את עמודת החבילה ואז לשלב אותה עם התחזיות שנעשו על ידי המודל שלנו.\n" ], "metadata": { "id": "fdgjzjkBwfWt" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Encode package column\n", "package_encode <- lm_pumpkins_recipe %>% \n", " prep() %>% \n", " bake(new_data = pumpkins_test) %>% \n", " select(package)\n", "\n", "\n", "# Bind encoded package column to the results\n", "lm_results <- lm_results %>% \n", " bind_cols(package_encode %>% \n", " rename(package_integer = package)) %>% \n", " relocate(package_integer, .after = package)\n", "\n", "\n", "# Print new results data frame\n", "lm_results %>% \n", " slice_head(n = 5)\n", "\n", "\n", "# Make a scatter plot\n", "lm_results %>% \n", " ggplot(mapping = aes(x = package_integer, y = price)) +\n", " geom_point(size = 1.6) +\n", " # Overlay a line of best fit\n", " geom_line(aes(y = .pred), color = \"orange\", size = 1.2) +\n", " xlab(\"package\")\n", " \n" ], "outputs": [], "metadata": { "id": "R0nw719lwkHE" } }, { "cell_type": "markdown", "source": [ "מעולה! כפי שניתן לראות, מודל הרגרסיה הליניארית לא מצליח להכליל בצורה טובה את הקשר בין חבילה למחיר המתאים לה.\n", "\n", "🎃 מזל טוב, הרגע יצרת מודל שיכול לעזור לחזות את המחיר של כמה סוגים של דלעות. שדה הדלעות שלך לחג יהיה מרהיב. אבל כנראה שתוכל ליצור מודל טוב יותר!\n", "\n", "## 5. בניית מודל רגרסיה פולינומי\n", "\n", "

\n", " \n", "

אינפוגרפיקה מאת דאסאני מדיפאלי
\n", "\n", "\n", "\n" ], "metadata": { "id": "HOCqJXLTwtWI" } }, { "cell_type": "markdown", "source": [ "לפעמים הנתונים שלנו עשויים שלא להיות בעלי קשר ליניארי, אך עדיין נרצה לחזות תוצאה. רגרסיה פולינומית יכולה לעזור לנו לבצע תחזיות עבור קשרים מורכבים יותר שאינם ליניאריים.\n", "\n", "לדוגמה, הקשר בין האריזה למחיר במאגר הנתונים של הדלעות שלנו. בעוד שלפעמים יש קשר ליניארי בין משתנים - ככל שהדלעת גדולה יותר בנפח, כך המחיר גבוה יותר - לעיתים קשרים אלו אינם יכולים להיות מוצגים כמישור או כקו ישר.\n", "\n", "> ✅ הנה [עוד כמה דוגמאות](https://online.stat.psu.edu/stat501/lesson/9/9.8) לנתונים שיכולים להשתמש ברגרסיה פולינומית \n", ">\n", "> הסתכלו שוב על הקשר בין הזן למחיר בגרף הקודם. האם פיזור הנתונים הזה נראה כאילו הוא חייב להיות מנותח באמצעות קו ישר? אולי לא. במקרה כזה, תוכלו לנסות רגרסיה פולינומית. \n", ">\n", "> ✅ פולינומים הם ביטויים מתמטיים שעשויים לכלול משתנה אחד או יותר ומקדמים \n", "\n", "#### אימון מודל רגרסיה פולינומית באמצעות קבוצת האימון \n", "\n", "רגרסיה פולינומית יוצרת *קו מעוקל* שמתאים טוב יותר לנתונים שאינם ליניאריים.\n", "\n", "בואו נראה האם מודל פולינומי יבצע תחזיות טובות יותר. נעקוב אחר תהליך דומה לזה שעשינו קודם:\n", "\n", "- יצירת מתכון שמפרט את שלבי העיבוד המקדימים שיש לבצע על הנתונים שלנו כדי להכין אותם למידול, כלומר: קידוד משתנים וחישוב פולינומים בדרגה *n* \n", "\n", "- בניית מפרט מודל \n", "\n", "- שילוב המתכון ומפרט המודל לתוך זרימת עבודה \n", "\n", "- יצירת מודל על ידי התאמת זרימת העבודה \n", "\n", "- הערכת ביצועי המודל על נתוני הבדיקה \n", "\n", "בואו נתחיל! \n" ], "metadata": { "id": "VcEIpRV9wzYr" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Specify a recipe\r\n", "poly_pumpkins_recipe <-\r\n", " recipe(price ~ package, data = pumpkins_train) %>%\r\n", " step_integer(all_predictors(), zero_based = TRUE) %>% \r\n", " step_poly(all_predictors(), degree = 4)\r\n", "\r\n", "\r\n", "# Create a model specification\r\n", "poly_spec <- linear_reg() %>% \r\n", " set_engine(\"lm\") %>% \r\n", " set_mode(\"regression\")\r\n", "\r\n", "\r\n", "# Bundle recipe and model spec into a workflow\r\n", "poly_wf <- workflow() %>% \r\n", " add_recipe(poly_pumpkins_recipe) %>% \r\n", " add_model(poly_spec)\r\n", "\r\n", "\r\n", "# Create a model\r\n", "poly_wf_fit <- poly_wf %>% \r\n", " fit(data = pumpkins_train)\r\n", "\r\n", "\r\n", "# Print learned model coefficients\r\n", "poly_wf_fit\r\n", "\r\n", " " ], "outputs": [], "metadata": { "id": "63n_YyRXw3CC" } }, { "cell_type": "markdown", "source": [ "#### הערכת ביצועי המודל\n", "\n", "👏👏 יצרת מודל פולינומי, בוא נעשה תחזיות על קבוצת הבדיקה!\n" ], "metadata": { "id": "-LHZtztSxDP0" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Make price predictions on test data\r\n", "poly_results <- poly_wf_fit %>% predict(new_data = pumpkins_test) %>% \r\n", " bind_cols(pumpkins_test %>% select(c(package, price))) %>% \r\n", " relocate(.pred, .after = last_col())\r\n", "\r\n", "\r\n", "# Print the results\r\n", "poly_results %>% \r\n", " slice_head(n = 10)" ], "outputs": [], "metadata": { "id": "YUFpQ_dKxJGx" } }, { "cell_type": "markdown", "source": [ "בואו נבדוק איך המודל ביצע על קבוצת הבדיקה באמצעות `yardstick::metrics()`.\n" ], "metadata": { "id": "qxdyj86bxNGZ" } }, { "cell_type": "code", "execution_count": null, "source": [ "metrics(data = poly_results, truth = price, estimate = .pred)" ], "outputs": [], "metadata": { "id": "8AW5ltkBxXDm" } }, { "cell_type": "markdown", "source": [ "🤩🤩 ביצועים הרבה יותר טובים.\n", "\n", "ה-`rmse` ירד מכ-7 לכ-3, מה שמעיד על ירידה בשגיאה בין המחיר האמיתי למחיר החזוי. אפשר *בערך* לפרש זאת כמשמעות שהתחזיות השגויות שגויות בממוצע בכ-3 דולר. ה-`rsq` עלה מכ-0.4 לכ-0.8.\n", "\n", "כל המדדים הללו מצביעים על כך שהמודל הפולינומי מתפקד הרבה יותר טוב מהמודל הליניארי. עבודה טובה!\n", "\n", "בואו נראה אם נוכל להמחיש את זה!\n" ], "metadata": { "id": "6gLHNZDwxYaS" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Bind encoded package column to the results\r\n", "poly_results <- poly_results %>% \r\n", " bind_cols(package_encode %>% \r\n", " rename(package_integer = package)) %>% \r\n", " relocate(package_integer, .after = package)\r\n", "\r\n", "\r\n", "# Print new results data frame\r\n", "poly_results %>% \r\n", " slice_head(n = 5)\r\n", "\r\n", "\r\n", "# Make a scatter plot\r\n", "poly_results %>% \r\n", " ggplot(mapping = aes(x = package_integer, y = price)) +\r\n", " geom_point(size = 1.6) +\r\n", " # Overlay a line of best fit\r\n", " geom_line(aes(y = .pred), color = \"midnightblue\", size = 1.2) +\r\n", " xlab(\"package\")\r\n" ], "outputs": [], "metadata": { "id": "A83U16frxdF1" } }, { "cell_type": "markdown", "source": [ "אתם יכולים לראות קו מעוקל שמתאים לנתונים שלכם בצורה טובה יותר! 🤩\n", "\n", "אתם יכולים להפוך את זה לחלק יותר על ידי העברת נוסחה פולינומית ל-`geom_smooth` כך:\n" ], "metadata": { "id": "4U-7aHOVxlGU" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Make a scatter plot\r\n", "poly_results %>% \r\n", " ggplot(mapping = aes(x = package_integer, y = price)) +\r\n", " geom_point(size = 1.6) +\r\n", " # Overlay a line of best fit\r\n", " geom_smooth(method = lm, formula = y ~ poly(x, degree = 4), color = \"midnightblue\", size = 1.2, se = FALSE) +\r\n", " xlab(\"package\")" ], "outputs": [], "metadata": { "id": "5vzNT0Uexm-w" } }, { "cell_type": "markdown", "source": [ "ממש כמו עקומה חלקה! 🤩\n", "\n", "כך תוכל לבצע תחזית חדשה:\n" ], "metadata": { "id": "v9u-wwyLxq4G" } }, { "cell_type": "code", "execution_count": null, "source": [ "# Make a hypothetical data frame\r\n", "hypo_tibble <- tibble(package = \"bushel baskets\")\r\n", "\r\n", "# Make predictions using linear model\r\n", "lm_pred <- lm_wf_fit %>% predict(new_data = hypo_tibble)\r\n", "\r\n", "# Make predictions using polynomial model\r\n", "poly_pred <- poly_wf_fit %>% predict(new_data = hypo_tibble)\r\n", "\r\n", "# Return predictions in a list\r\n", "list(\"linear model prediction\" = lm_pred, \r\n", " \"polynomial model prediction\" = poly_pred)\r\n" ], "outputs": [], "metadata": { "id": "jRPSyfQGxuQv" } }, { "cell_type": "markdown", "source": [ "התחזית של `polynomial model` בהחלט הגיונית, בהתחשב בגרפי הפיזור של `price` ו-`package`! ואם זהו מודל טוב יותר מהקודם, בהתבסס על אותם נתונים, תצטרך לתכנן תקציב לדלעות היקרות יותר הללו!\n", "\n", "🏆 כל הכבוד! יצרת שני מודלים רגרסיה בשיעור אחד. בחלק האחרון על רגרסיה, תלמד על רגרסיה לוגיסטית כדי לקבוע קטגוריות.\n", "\n", "## **🚀אתגר**\n", "\n", "בדוק מספר משתנים שונים במחברת זו כדי לראות כיצד הקורלציה משפיעה על דיוק המודל.\n", "\n", "## [**שאלון לאחר השיעור**](https://gray-sand-07a10f403.1.azurestaticapps.net/quiz/14/)\n", "\n", "## **סקירה ולימוד עצמי**\n", "\n", "בשיעור זה למדנו על רגרסיה ליניארית. ישנם סוגים חשובים נוספים של רגרסיה. קרא על טכניקות Stepwise, Ridge, Lasso ו-Elasticnet. קורס טוב ללמוד ממנו הוא [קורס הלמידה הסטטיסטית של סטנפורד](https://online.stanford.edu/courses/sohs-ystatslearning-statistical-learning).\n", "\n", "אם אתה רוצה ללמוד יותר על השימוש במסגרת המדהימה של Tidymodels, אנא בדוק את המשאבים הבאים:\n", "\n", "- אתר Tidymodels: [התחל עם Tidymodels](https://www.tidymodels.org/start/)\n", "\n", "- מקס קון וג'וליה סילג, [*Tidy Modeling with R*](https://www.tmwr.org/)*.*\n", "\n", "###### **תודה ל:**\n", "\n", "[אליסון הורסט](https://twitter.com/allison_horst?lang=en) על יצירת האיורים המדהימים שהופכים את R למזמינה ומרתקת יותר. מצא איורים נוספים בגלריה שלה [כאן](https://www.google.com/url?q=https://github.com/allisonhorst/stats-illustrations&sa=D&source=editors&ust=1626380772530000&usg=AOvVaw3zcfyCizFQZpkSLzxiiQEM).\n" ], "metadata": { "id": "8zOLOWqMxzk5" } }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n---\n\n**כתב ויתור**: \nמסמך זה תורגם באמצעות שירות תרגום מבוסס בינה מלאכותית [Co-op Translator](https://github.com/Azure/co-op-translator). למרות שאנו שואפים לדיוק, יש לקחת בחשבון שתרגומים אוטומטיים עשויים להכיל שגיאות או אי דיוקים. המסמך המקורי בשפתו המקורית צריך להיחשב כמקור סמכותי. עבור מידע קריטי, מומלץ להשתמש בתרגום מקצועי על ידי אדם. איננו נושאים באחריות לאי הבנות או לפרשנויות שגויות הנובעות משימוש בתרגום זה.\n" ] } ] }