{ "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-08-29T14:44:06+00:00", "source_file": "2-Regression/3-Linear/solution/R/lesson_3-R.ipynb", "language_code": "ar" } }, "cells": [ { "cell_type": "markdown", "source": [ "# بناء نموذج انحدار: نماذج الانحدار الخطي والمتعدد\n" ], "metadata": { "id": "EgQw8osnsUV-" } }, { "cell_type": "markdown", "source": [ "## الانحدار الخطي والانحدار متعدد الحدود لتسعير القرع - الدرس الثالث\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", "كما تعلمت في الدرس الأول، الهدف من تمرين الانحدار الخطي هو القدرة على رسم *خط* *أفضل تطابق* لـ:\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", " رسم توضيحي بواسطة Jen Looper\n", ">\n", "> أولاً، احسب الميل `b`.\n", ">\n", "> بمعنى آخر، وبالإشارة إلى سؤال البيانات الأصلية الخاصة بالقرع: \"توقع سعر القرع لكل بوشل حسب الشهر\"، سيكون `X` هو السعر و`Y` هو شهر البيع.\n", ">\n", "> ![](../../../../../../translated_images/calculation.989aa7822020d9d0ba9fc781f1ab5192f3421be86ebb88026528aef33c37b0d8.ar.png)\n", " رسم توضيحي بواسطة Jen Looper\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" ], "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": [ "في روح المغامرة الخالصة، دعونا نستكشف [`حزمة janitor`](../../../../../../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": [ "الكثير من الترتيب 🧹! الآن، رقصة مع البيانات باستخدام `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": [ "ماذا لو أردنا التنبؤ بـ `السعر` لقرع بناءً على أعمدة `المدينة` أو `الحزمة` التي تكون من نوع نصي؟ أو بشكل أبسط، كيف يمكننا العثور على الارتباط (الذي يتطلب أن تكون مدخلاته رقمية) بين، على سبيل المثال، `الحزمة` و `السعر`؟ 🤷🤷\n", "\n", "نماذج التعلم الآلي تعمل بشكل أفضل مع الميزات الرقمية بدلاً من القيم النصية، لذا عادةً ما تحتاج إلى تحويل الميزات الفئوية إلى تمثيلات رقمية.\n", "\n", "هذا يعني أننا بحاجة إلى إيجاد طريقة لإعادة صياغة المتنبئات لدينا لجعلها أسهل للاستخدام بشكل فعال من قبل النموذج، وهي عملية تُعرف بـ `هندسة الميزات`.\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` هو إطار بيانات يمكننا إجراء العمليات الحسابية عليه.\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", "\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": [ "أحيانًا قد لا تكون بياناتنا ذات علاقة خطية، ولكننا نرغب مع ذلك في التنبؤ بالنتائج. يمكن أن يساعدنا الانحدار متعدد الحدود (Polynomial Regression) في إجراء التنبؤات للعلاقات الأكثر تعقيدًا وغير الخطية.\n", "\n", "خذ على سبيل المثال العلاقة بين العبوة والسعر في مجموعة بيانات القرع الخاصة بنا. في بعض الأحيان، تكون هناك علاقة خطية بين المتغيرات - كلما زاد حجم القرع (من حيث الحجم)، زاد السعر - ولكن في أحيان أخرى، لا يمكن تمثيل هذه العلاقات كطائرة أو خط مستقيم.\n", "\n", "> ✅ إليك [بعض الأمثلة الأخرى](https://online.stat.psu.edu/stat501/lesson/9/9.8) على بيانات يمكن استخدام الانحدار متعدد الحدود معها.\n", ">\n", "> ألقِ نظرة أخرى على العلاقة بين النوع والسعر في الرسم البياني السابق. هل يبدو أن هذا الرسم النقطي يجب تحليله بالضرورة باستخدام خط مستقيم؟ ربما لا. في هذه الحالة، يمكنك تجربة الانحدار متعدد الحدود.\n", ">\n", "> ✅ الحدوديات (Polynomials) هي تعبيرات رياضية قد تتكون من متغير واحد أو أكثر ومعاملات.\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", "- ماكس كون وجوليا سيلج، [*النمذجة المنظمة باستخدام 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" ] } ] }