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.
685 lines
37 KiB
685 lines
37 KiB
{
|
|
"cells": [
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## بناء نموذج الانحدار اللوجستي - الدرس الرابع\n",
|
|
"\n",
|
|
"\n",
|
|
"\n",
|
|
"#### **[اختبار ما قبل المحاضرة](https://gray-sand-07a10f403.1.azurestaticapps.net/quiz/15/)**\n",
|
|
"\n",
|
|
"#### المقدمة\n",
|
|
"\n",
|
|
"في هذا الدرس الأخير حول الانحدار، وهو أحد تقنيات التعلم الآلي *الكلاسيكية* الأساسية، سنلقي نظرة على الانحدار اللوجستي. يمكنك استخدام هذه التقنية لاكتشاف الأنماط للتنبؤ بالفئات الثنائية. هل هذه الحلوى تحتوي على شوكولاتة أم لا؟ هل هذا المرض معدٍ أم لا؟ هل سيختار هذا العميل هذا المنتج أم لا؟\n",
|
|
"\n",
|
|
"في هذا الدرس، ستتعلم:\n",
|
|
"\n",
|
|
"- تقنيات الانحدار اللوجستي\n",
|
|
"\n",
|
|
"✅ عمّق فهمك للعمل مع هذا النوع من الانحدار في هذا [الوحدة التعليمية](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",
|
|
"\n",
|
|
"\n",
|
|
"### تصنيفات أخرى\n",
|
|
"\n",
|
|
"هناك أنواع أخرى من الانحدار اللوجستي، بما في ذلك متعدد الفئات والرتبي:\n",
|
|
"\n",
|
|
"- **متعدد الفئات**، والذي يتضمن وجود أكثر من فئة واحدة - \"برتقالي، أبيض، ومخطط\".\n",
|
|
"\n",
|
|
"- **رتبي**، والذي يتضمن فئات مرتبة، وهو مفيد إذا أردنا ترتيب النتائج بشكل منطقي، مثل القرع الذي يتم ترتيبه حسب عدد محدود من الأحجام (صغير جدًا، صغير، متوسط، كبير، كبير جدًا، كبير جدًا جدًا).\n",
|
|
"\n",
|
|
"\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": [
|
|
"يمكنك دائمًا إلقاء نظرة سريعة على إطار البيانات الجديد الخاص بك باستخدام وظيفة [*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 encoding)، مما يعني أن كل فئة يتم تمثيلها بعمود ثنائي: تكون القيمة المشفرة مساوية لـ 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": [
|
|
"✅ ما هي فوائد استخدام الترميز الترتيبي لعمود حجم العنصر؟\n",
|
|
"\n",
|
|
"### تحليل العلاقات بين المتغيرات\n",
|
|
"\n",
|
|
"الآن بعد أن قمنا بمعالجة البيانات مسبقًا، يمكننا تحليل العلاقات بين الميزات والتسمية لفهم مدى قدرة النموذج على التنبؤ بالتسمية بناءً على الميزات. أفضل طريقة لإجراء هذا النوع من التحليل هي رسم البيانات. \n",
|
|
"سنستخدم مرة أخرى وظيفة ggplot geom_boxplot_، لتصور العلاقات بين حجم العنصر، النوع، واللون في مخطط تصنيفي. لتحسين رسم البيانات، سنستخدم عمود حجم العنصر المشفر وعمود النوع غير المشفر.\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",
|
|
"بما أن اللون هو فئة ثنائية (أبيض أو غير ذلك)، فإنه يحتاج إلى \"[نهج متخصص](https://github.com/rstudio/cheatsheets/blob/main/data-visualization.pdf)\" للتصور.\n",
|
|
"\n",
|
|
"جرّب `مخطط السرب` لعرض توزيع اللون بالنسبة لحجم العنصر.\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": [
|
|
"الآن بعد أن أصبح لدينا وصفة ومواصفات نموذج، نحتاج إلى إيجاد طريقة لدمجهما معًا في كائن يقوم أولاً بمعالجة البيانات مسبقًا (التحضير + الخبز خلف الكواليس)، ثم تدريب النموذج على البيانات المعالجة مسبقًا، وأيضًا يتيح إمكانية القيام بأنشطة معالجة لاحقة.\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 معدل الإيجابيات الحقيقية/الحساسية على المحور الرأسي، ومعدل الإيجابيات الكاذبة/1-النوعية على المحور الأفقي. وبالتالي، فإن انحدار المنحنى والمسافة بين خط المنتصف والمنحنى لهما أهمية: الهدف هو الحصول على منحنى يتجه بسرعة إلى الأعلى ويتجاوز الخط. في حالتنا، هناك إيجابيات كاذبة في البداية، ثم يتجه الخط إلى الأعلى ويتجاوز بشكل صحيح.\n",
|
|
"\n",
|
|
"أخيرًا، دعونا نستخدم `yardstick::roc_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-08-29T14:51:01+00:00",
|
|
"source_file": "2-Regression/4-Logistic/solution/R/lesson_4-R.ipynb",
|
|
"language_code": "ar"
|
|
}
|
|
},
|
|
"nbformat": 4,
|
|
"nbformat_minor": 1
|
|
} |