{ "nbformat": 4, "nbformat_minor": 2, "metadata": { "colab": { "name": "lesson_2-R.ipynb", "provenance": [], "collapsed_sections": [], "toc_visible": true }, "kernelspec": { "name": "ir", "display_name": "R" }, "language_info": { "name": "R" }, "coopTranslator": { "original_hash": "f3c335f9940cfd76528b3ef918b9b342", "translation_date": "2025-09-04T01:44:39+00:00", "source_file": "2-Regression/2-Data/solution/R/lesson_2-R.ipynb", "language_code": "fa" } }, "cells": [ { "cell_type": "markdown", "source": [ "# ساخت یک مدل رگرسیون: آمادهسازی و تجسم دادهها\n", "\n", "## **رگرسیون خطی برای کدو تنبل - درس دوم**\n", "#### مقدمه\n", "\n", "حالا که ابزارهای لازم برای شروع ساخت مدلهای یادگیری ماشین با استفاده از Tidymodels و Tidyverse را در اختیار دارید، آمادهاید تا سوالاتی از دادههای خود بپرسید. هنگام کار با دادهها و اعمال راهحلهای یادگیری ماشین، بسیار مهم است که بدانید چگونه سوالات درست بپرسید تا بتوانید به درستی از پتانسیلهای مجموعه داده خود استفاده کنید.\n", "\n", "در این درس، شما یاد خواهید گرفت:\n", "\n", "- چگونه دادههای خود را برای ساخت مدل آماده کنید.\n", "\n", "- چگونه از `ggplot2` برای تجسم دادهها استفاده کنید.\n", "\n", "سوالی که نیاز به پاسخ آن دارید، تعیین میکند که از چه نوع الگوریتمهای یادگیری ماشین استفاده خواهید کرد. همچنین کیفیت پاسخی که دریافت میکنید، به شدت به ماهیت دادههای شما بستگی دارد.\n", "\n", "بیایید این موضوع را با انجام یک تمرین عملی بررسی کنیم.\n", "\n", "
\n",
" \n",
"
\n",
"\n",
"> یک یادآوری: عملگر پایپ (`%>%`) عملیات را به صورت منطقی و پشت سر هم انجام میدهد و یک شیء را به جلو به یک تابع یا عبارت ارسال میکند. میتوانید عملگر پایپ را به این صورت تصور کنید که در کد شما به معنای \"و سپس\" است.\n"
],
"metadata": {
"id": "REWcIv9yX29v"
}
},
{
"cell_type": "markdown",
"source": [
"## ۲. بررسی دادههای ناقص\n",
"\n",
"یکی از رایجترین مشکلاتی که دانشمندان داده باید با آن مواجه شوند، دادههای ناقص یا گمشده است. در زبان R، مقادیر گمشده یا ناشناخته با یک مقدار خاص به نام `NA` (مخفف Not Available) نمایش داده میشوند.\n",
"\n",
"اما چگونه میتوانیم بفهمیم که یک فریم داده شامل مقادیر گمشده است؟\n",
"
\n",
"- یکی از روشهای ساده استفاده از تابع پایه R به نام `anyNA` است که اشیاء منطقی `TRUE` یا `FALSE` را برمیگرداند.\n"
],
"metadata": {
"id": "Zxfb3AM5YbUe"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"pumpkins %>% \n",
" anyNA()"
],
"outputs": [],
"metadata": {
"id": "G--DQutAYltj"
}
},
{
"cell_type": "markdown",
"source": [
"عالی است، به نظر میرسد برخی دادهها وجود ندارند! این میتواند نقطهی خوبی برای شروع باشد.\n",
"\n",
"- یک روش دیگر استفاده از تابع `is.na()` است که نشان میدهد کدام عناصر ستون به صورت جداگانه با مقدار منطقی `TRUE` گم شدهاند.\n"
],
"metadata": {
"id": "mU-7-SB6YokF"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"pumpkins %>% \n",
" is.na() %>% \n",
" head(n = 7)"
],
"outputs": [],
"metadata": {
"id": "W-DxDOR4YxSW"
}
},
{
"cell_type": "markdown",
"source": [
"باشه، کار انجام شد اما با یک دیتافریم بزرگ مثل این، بررسی تکتک سطرها و ستونها بهصورت جداگانه غیربهینه و عملاً غیرممکن است 😴.\n",
"\n",
"- یک روش شهودیتر این است که مجموع مقادیر گمشده را برای هر ستون محاسبه کنیم:\n"
],
"metadata": {
"id": "xUWxipKYY0o7"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"pumpkins %>% \n",
" is.na() %>% \n",
" colSums()"
],
"outputs": [],
"metadata": {
"id": "ZRBWV6P9ZArL"
}
},
{
"cell_type": "markdown",
"source": [
"خیلی بهتر! دادههایی کم هستند، اما شاید برای انجام این کار مهم نباشند. بیایید ببینیم تحلیل بیشتر چه نتایجی به همراه دارد.\n",
"\n",
"> همراه با مجموعههای فوقالعادهای از پکیجها و توابع، R مستندات بسیار خوبی دارد. برای مثال، از `help(colSums)` یا `?colSums` استفاده کنید تا اطلاعات بیشتری درباره این تابع به دست آورید.\n"
],
"metadata": {
"id": "9gv-crB6ZD1Y"
}
},
{
"cell_type": "markdown",
"source": [
"## ۳. Dplyr: دستور زبانی برای دستکاری دادهها\n",
"\n",
"
\n",
" \n",
"
\n"
],
"metadata": {
"id": "i5o33MQBZWWw"
}
},
{
"cell_type": "markdown",
"source": [
"#### dplyr::select()\n",
"\n",
"تابع `select()` در بسته `dplyr` به شما کمک میکند ستونهایی را که میخواهید نگه دارید یا حذف کنید، انتخاب کنید.\n",
"\n",
"برای اینکه کار با دیتافریم شما آسانتر شود، میتوانید با استفاده از `select()` چند ستون آن را حذف کرده و فقط ستونهای مورد نیاز خود را نگه دارید.\n",
"\n",
"برای مثال، در این تمرین، تحلیل ما شامل ستونهای `Package`، `Low Price`، `High Price` و `Date` خواهد بود. بیایید این ستونها را انتخاب کنیم.\n"
],
"metadata": {
"id": "x3VGMAGBZiUr"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"# Select desired columns\n",
"pumpkins <- pumpkins %>% \n",
" select(Package, `Low Price`, `High Price`, Date)\n",
"\n",
"\n",
"# Print data set\n",
"pumpkins %>% \n",
" slice_head(n = 5)"
],
"outputs": [],
"metadata": {
"id": "F_FgxQnVZnM0"
}
},
{
"cell_type": "markdown",
"source": [
"#### dplyr::mutate()\n",
"\n",
"`mutate()` یک تابع در بسته `dplyr` است که به شما کمک میکند ستونهای جدید ایجاد کنید یا ستونهای موجود را تغییر دهید، در حالی که ستونهای قبلی را حفظ میکنید.\n",
"\n",
"ساختار کلی `mutate` به این صورت است:\n",
"\n",
"`data %>% mutate(new_column_name = what_it_contains)`\n",
"\n",
"بیایید با استفاده از ستون `Date` چند عملیات انجام دهیم تا نحوه کار `mutate` را بررسی کنیم:\n",
"\n",
"1. تاریخها (که در حال حاضر از نوع کاراکتر هستند) را به فرمت ماه تبدیل کنیم (این تاریخها به سبک آمریکایی هستند، بنابراین فرمت آنها `MM/DD/YYYY` است).\n",
"\n",
"2. ماه را از تاریخها استخراج کرده و در یک ستون جدید ذخیره کنیم.\n",
"\n",
"در زبان R، بسته [lubridate](https://lubridate.tidyverse.org/) کار با دادههای تاریخ و زمان را آسانتر میکند. بنابراین، بیایید از `dplyr::mutate()`، `lubridate::mdy()`، `lubridate::month()` استفاده کنیم و ببینیم چگونه میتوانیم اهداف بالا را محقق کنیم. همچنین میتوانیم ستون `Date` را حذف کنیم، زیرا در عملیات بعدی دیگر به آن نیازی نخواهیم داشت.\n"
],
"metadata": {
"id": "2KKo0Ed9Z1VB"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"# Load lubridate\n",
"library(lubridate)\n",
"\n",
"pumpkins <- pumpkins %>% \n",
" # Convert the Date column to a date object\n",
" mutate(Date = mdy(Date)) %>% \n",
" # Extract month from Date\n",
" mutate(Month = month(Date)) %>% \n",
" # Drop Date column\n",
" select(-Date)\n",
"\n",
"# View the first few rows\n",
"pumpkins %>% \n",
" slice_head(n = 7)"
],
"outputs": [],
"metadata": {
"id": "5joszIVSZ6xe"
}
},
{
"cell_type": "markdown",
"source": [
"هورا! 🤩\n",
"\n",
"حالا بیایید یک ستون جدید به نام `Price` ایجاد کنیم که نشاندهنده قیمت متوسط یک کدو تنبل است. سپس میانگین ستونهای `Low Price` و `High Price` را محاسبه میکنیم تا ستون جدید Price را پر کنیم.\n"
],
"metadata": {
"id": "nIgLjNMCZ-6Y"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"# Create a new column Price\n",
"pumpkins <- pumpkins %>% \n",
" mutate(Price = (`Low Price` + `High Price`)/2)\n",
"\n",
"# View the first few rows of the data\n",
"pumpkins %>% \n",
" slice_head(n = 5)"
],
"outputs": [],
"metadata": {
"id": "Zo0BsqqtaJw2"
}
},
{
"cell_type": "markdown",
"source": [
"بله! 💪\n",
"\n",
"\"اما صبر کن!\" ممکن است بعد از مرور کل مجموعه داده با استفاده از `View(pumpkins)` بگویی، \"اینجا چیزی عجیب به نظر میرسد!\" 🤔\n",
"\n",
"اگر به ستون `Package` نگاه کنی، کدوها در پیکربندیهای مختلفی فروخته میشوند. برخی در اندازههای `1 1/9 bushel` فروخته میشوند، برخی در اندازههای `1/2 bushel`، برخی به ازای هر کدو، برخی به ازای هر پوند، و برخی در جعبههای بزرگی با عرضهای متغیر.\n",
"\n",
"بیایید این را بررسی کنیم:\n"
],
"metadata": {
"id": "p77WZr-9aQAR"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"# Verify the distinct observations in Package column\n",
"pumpkins %>% \n",
" distinct(Package)"
],
"outputs": [],
"metadata": {
"id": "XISGfh0IaUy6"
}
},
{
"cell_type": "markdown",
"source": [
"شگفتانگیز!👏\n",
"\n",
"به نظر میرسد وزن کردن کدو تنبلها به طور یکنواخت بسیار دشوار است، بنابراین بیایید آنها را فیلتر کنیم و فقط کدو تنبلهایی را انتخاب کنیم که رشته *bushel* در ستون `Package` دارند و این را در یک دادهفریم جدید به نام `new_pumpkins` قرار دهیم.\n"
],
"metadata": {
"id": "7sMjiVujaZxY"
}
},
{
"cell_type": "markdown",
"source": [
"#### dplyr::filter() و stringr::str_detect()\n",
"\n",
"[`dplyr::filter()`](https://dplyr.tidyverse.org/reference/filter.html): زیرمجموعهای از دادهها ایجاد میکند که فقط شامل **ردیفهایی** است که شرایط شما را برآورده میکنند. در این مثال، کدوهایی که رشته *bushel* در ستون `Package` آنها وجود دارد.\n",
"\n",
"[stringr::str_detect()](https://stringr.tidyverse.org/reference/str_detect.html): حضور یا عدم حضور یک الگو در یک رشته را تشخیص میدهد.\n",
"\n",
"بسته [`stringr`](https://github.com/tidyverse/stringr) توابع سادهای برای عملیات رایج روی رشتهها ارائه میدهد.\n"
],
"metadata": {
"id": "L8Qfcs92ageF"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"# Retain only pumpkins with \"bushel\"\n",
"new_pumpkins <- pumpkins %>% \n",
" filter(str_detect(Package, \"bushel\"))\n",
"\n",
"# Get the dimensions of the new data\n",
"dim(new_pumpkins)\n",
"\n",
"# View a few rows of the new data\n",
"new_pumpkins %>% \n",
" slice_head(n = 5)"
],
"outputs": [],
"metadata": {
"id": "hy_SGYREampd"
}
},
{
"cell_type": "markdown",
"source": [
"میتوانید ببینید که ما دادهها را به حدود ۴۱۵ ردیف محدود کردهایم که شامل کدو تنبل به صورت بوشل است. 🤩 \n",
"
\n"
],
"metadata": {
"id": "VrDwF031avlR"
}
},
{
"cell_type": "markdown",
"source": [
"#### dplyr::case_when()\n",
"\n",
"**اما صبر کنید! هنوز یک کار دیگر باقی مانده است**\n",
"\n",
"متوجه شدید که مقدار بوشل در هر سطر متفاوت است؟ باید قیمتگذاری را نرمالسازی کنید تا قیمت را بر اساس هر بوشل نشان دهید، نه بر اساس ۱ ۱/۹ یا ۱/۲ بوشل. وقت آن است که کمی ریاضی انجام دهید تا آن را استاندارد کنید.\n",
"\n",
"ما از تابع [`case_when()`](https://dplyr.tidyverse.org/reference/case_when.html) استفاده خواهیم کرد تا ستون Price را بر اساس برخی شرایط *تغییر دهیم*. `case_when` به شما این امکان را میدهد که چندین عبارت `if_else()` را به صورت برداری بنویسید.\n"
],
"metadata": {
"id": "mLpw2jH4a0tx"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"# Convert the price if the Package contains fractional bushel values\n",
"new_pumpkins <- new_pumpkins %>% \n",
" mutate(Price = case_when(\n",
" str_detect(Package, \"1 1/9\") ~ Price/(1 + 1/9),\n",
" str_detect(Package, \"1/2\") ~ Price/(1/2),\n",
" TRUE ~ Price))\n",
"\n",
"# View the first few rows of the data\n",
"new_pumpkins %>% \n",
" slice_head(n = 30)"
],
"outputs": [],
"metadata": {
"id": "P68kLVQmbM6I"
}
},
{
"cell_type": "markdown",
"source": [
"اکنون میتوانیم قیمت هر واحد را بر اساس اندازه بوشل تحلیل کنیم. با این حال، تمام این بررسی بوشلهای کدو تنبل نشان میدهد که چقدر `مهم` است که `ماهیت دادههای خود را درک کنید`!\n",
"\n",
"> ✅ طبق گفته [The Spruce Eats](https://www.thespruceeats.com/how-much-is-a-bushel-1389308)، وزن یک بوشل به نوع محصول بستگی دارد، زیرا این یک اندازهگیری حجمی است. \"برای مثال، یک بوشل گوجهفرنگی باید ۵۶ پوند وزن داشته باشد... برگها و سبزیجات فضای بیشتری را با وزن کمتر اشغال میکنند، بنابراین یک بوشل اسفناج فقط ۲۰ پوند است.\" این موضوع کاملاً پیچیده است! بیایید خود را درگیر تبدیل بوشل به پوند نکنیم و به جای آن قیمت را بر اساس بوشل تعیین کنیم. تمام این بررسی بوشلهای کدو تنبل نشان میدهد که چقدر مهم است که ماهیت دادههای خود را درک کنید!\n",
">\n",
"> ✅ آیا متوجه شدید که کدو تنبلهایی که به صورت نیمبوشل فروخته میشوند بسیار گران هستند؟ میتوانید دلیل آن را پیدا کنید؟ نکته: کدو تنبلهای کوچک بسیار گرانتر از کدو تنبلهای بزرگ هستند، احتمالاً به این دلیل که تعداد بیشتری از آنها در هر بوشل وجود دارد، با توجه به فضای خالیای که یک کدو تنبل بزرگ و توخالی اشغال میکند.\n"
],
"metadata": {
"id": "pS2GNPagbSdb"
}
},
{
"cell_type": "markdown",
"source": [
"حالا در نهایت، برای ماجراجویی خالص 💁♀️، بیایید ستون ماه را به اولین موقعیت منتقل کنیم، یعنی `قبل از` ستون `Package`.\n",
"\n",
"برای تغییر موقعیت ستونها از `dplyr::relocate()` استفاده میشود.\n"
],
"metadata": {
"id": "qql1SowfbdnP"
}
},
{
"cell_type": "code",
"execution_count": null,
"source": [
"# Create a new data frame new_pumpkins\n",
"new_pumpkins <- new_pumpkins %>% \n",
" relocate(Month, .before = Package)\n",
"\n",
"new_pumpkins %>% \n",
" slice_head(n = 7)"
],
"outputs": [],
"metadata": {
"id": "JJ1x6kw8bixF"
}
},
{
"cell_type": "markdown",
"source": [
"کارت عالی بود!👌 حالا یک مجموعه داده تمیز و مرتب در اختیار داری که میتوانی مدل رگرسیون جدیدت را بر اساس آن بسازی!\n",
"
\n"
],
"metadata": {
"id": "y8TJ0Za_bn5Y"
}
},
{
"cell_type": "markdown",
"source": [
"## ۴. مصورسازی دادهها با ggplot2\n",
"\n",
"
\n",
" \n",
"