کتابخانه dplyr و دستورات Select ،Filter ،Arrange و Pipeline در R — راهنمای کاربردی

کتابخانه dplyr شامل بسیاری از توابع ارزشمند مرتبط با «پاکسازی دادهها» (Data Cleaning) است. در نوشتارهای دیگر وبلاگ فرادرس با بعضی از ابزارهای کاربردی این کتابخانه مثل گروه توابع Join آشنا شدید. همچنین به منظور مدیریت دادههای ناموجود (گمشده) در R نیز از این کتابخانه استفاده کردیم. در این نوشتار سعی میکنیم با ابزارهای دیگری از این کتابخانه مثل $$select()$$ ،$$filter()$$ ،$$arrange()$$ و Pipeline آشنا شویم.
توابع Select ،Filter ،Arrange و Pipeline
در این نوشتار به بررسی ابزارهای ارزشمندی از کتابخانه dplyr در زبان برنامهنویسی R میپردازیم که قادر هستند کار تبدیل دادهها را به خوبی انجام دهند. حتما در دیگر نوشتههای فرادرس خواندهاید که مرحله «پاکسازی دادهها» (Data Cleaning) یکی از بخشهای مهم فرآیند «دادهکاوی» (Data Mining) محسوب میشود. بنابراین این ابزارها در دادهکاوی نیز به کار خواهند آمد.
در این نوشتار از فایل دادهای به نام travel_times.csv استفاده میکنیم که شامل چهارده متغیر مختلف و ۲۰۰ مشاهده است. جدول زیر به معرفی متغیرهای این مجموعه داده پرداخته است. این مجموعه داده، مرتبط با اطلاعات سفرهای کاری یک فرد از خانه تا محل کارش در تاریخهای مختلف است.
نام متغیر | شرح | نوع متغیر |
X | شماره ردیف | عدد صحیح (Int) |
Date | تاریخ سفر | متغیر عامل (Fctr) |
StartTime | ساعت حرکت | متغیر عامل (Fctr) |
DayOfWeek | روز هفته | متغیر عامل (Fctr) |
GoingTo | مقصد | متغیر عامل (Fctr) |
MaxSpeed | حداکثر سرعت | عدد اعشاری (dbl) |
AvgSpeed | متوسط سرعت | عدد اعشاری (dbl) |
AvgMovingSpeed | متوسط سرعت جابجایی | عدد اعشاری (dbl) |
FuelEconomy | میزان مصرف سوخت | متغیر عامل (Fctr) |
TotalTime | کل زمان | عدد اعشاری (dbl) |
MovingTime | زمان جابجایی | عدد اعشاری (dbl) |
Take407All | استفاده از اتوبان ۴۰۷ | متغیر عامل (Fctr) |
Comments | یادداشت | متغیر عامل (Fctr) |
در مرحله اول دادهها را بارگذاری کرده و متغیرها را شناسایی میکنیم. کد زیر به این منظور تهیه شده است. مشخص است که برای دریافت این فایل باید به اینترنت متصل باشید.
ibrary(dplyr) PATH <- "https://raw.githubusercontent.com/thomaspernet/data_csv_r/master/data/travel_times.csv" df <- read.csv(PATH) glimpse(df)
ابتدا چارچوب داده (Data Frame) به نام df تشکیل شده و این دادهها در آن قرار میگیرد. از آنجایی که از تابع glimpse برای نمایش دادهها استفاده شده است، خروجی به صورت زیر خواهد.
## Observations: 205 ## Variables: 14 ## $ X <int> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, ... ## $ Date <fctr> 1/6/2012, 1/6/2012, 1/4/2012, 1/4/2012, 1/3/20... ## $ StartTime <fctr> 16:37, 08:20, 16:17, 07:53, 18:57, 07:57, 17:3... ## $ DayOfWeek <fctr> Friday, Friday, Wednesday, Wednesday, Tuesday,... ## $ GoingTo <fctr> Home, GSK, Home, GSK, Home, GSK, Home, GSK, GS... ## $ Distance <dbl> 51.29, 51.63, 51.27, 49.17, 51.15, 51.80, 51.37... ## $ MaxSpeed <dbl> 127.4, 130.3, 127.4, 132.3, 136.2, 135.8, 123.2... ## $ AvgSpeed <dbl> 78.3, 81.8, 82.0, 74.2, 83.4, 84.5, 82.9, 77.5,... ## $ AvgMovingSpeed <dbl> 84.8, 88.9, 85.8, 82.9, 88.1, 88.8, 87.3, 85.9,... ## $ FuelEconomy <fctr> , , , , , , -, -, 8.89, 8.89, 8.89, 8.89, 8.89... ## $ TotalTime <dbl> 39.3, 37.9, 37.5, 39.8, 36.8, 36.8, 37.2, 37.9,... ## $ MovingTime <dbl> 36.3, 34.9, 35.9, 35.6, 34.8, 35.0, 35.3, 34.3,... ## $ Take407All <fctr> No, No, No, No, No, No, No, No, No, No, No, No... ## $ Comments <fctr> , , , , , , , , , , , , , , , Put snow tires o...
همانطور که مشاهده میشود، بعضی از مشاهدات برای متغیر Comments دارای مقدار نیستند. بنابراین بهتر است که مشخص کنیم چه درصدی از مشاهدات برای این متغیر دارای مقدار ناموجود هستند. کد زیر این وظیفه را به خوبی انجام میدهد.
sum(df$Comments =="")
واضح است که مشاهداتی که برای متغیر Comments در چارچوب داده df دارای مقداری نیستند توسط تابع sum شمارش شده است. این مقدار برابر است با ۱۸۱ مشاهده که حدود ۹۰درصد کل مشاهدات است. بنابراین به نظر میرسد که این متغیر در تحلیل ما نقشی نخواهد داشت. بنابراین بهتر است که از تحلیل خارج شود.
به کمک $$select()$$ به راحتی میتوان متغیر Comments را کنار گذاشت و براساس بقه متغیرها کار تحلیل را به پیش برد.
انتخاب متغیرها با $$select()$$
شکل کلی $$select()$$ در ادامه دیده میشود. کافی است که نام چارچوب داده را به همراه متغیرهایی که لازم دارید به عنوان پارامترهای مورد نظر وارد کنید.
- `select(df, A, B ,C)`: Select the variables A, B and C from df dataset. - `select(df, A:C)`: Select all variables from A to C from df dataset. - `select(df, -C)`: Exclude C from the dataset from df dataset.
- در لیست بالا، سطر اول متغیرهای A,B و C از df را انتخاب میکند.
- سطر دوم نشان دهنده انتخاب همان متغیرها است ولی از عملگر «:» برای نشان دادن اولین و آخرین متغیر انتخابی، استفاده کرده است.
- سطر آخر نیز با توجه به عبارت «c-» نشانگر عدم انتخاب متغیر c است. به نظر میرسد که راهکار آخر برای ما مفید باشد. بنابراین کد زیر را برای حذف متغیر Comments به کار میبریم.
step_1_df <- select(df, -Comments) dim(df) dim(step_1_df)
حاصل انتخاب متغیرها در متغیر جدیدی به نام step_1_df ذخیره شده است. با استفاده از تابع $$dim()$$ میخواهیم ابعاد df را مشخص کنیم. خروجی نشان میدهد که تعداد مشاهدات برای df همان ۲۰۵ و تعداد متغیرها ۱۴ است. در حالیکه برای چارچوب داده step_1_df این ابعاد برابر با 205 مشاهده و ۱۳ متغیر است. به نظر میرسد که متغیر Comments از مجموعه داده حذف شده است.
انتخاب مشاهدات براساس $$filter()$$
در گام بعدی میخواهیم براساس مشاهداتی که مربوط به حرکت از خانه هستند محاسبات را به پیش ببریم. استفاده از $$filter()$$ در اینجا دقیقا همین عمل را انجام میدهد. شکل پارامترهای ان به صورت زیر است.
filter(df, condition) arguments: - df: dataset used to filter the data - condition: Condition used to filter the data
مشخص است که منظور از condition شرطی است که باید بر روی مشاهدات اعمال شود تا گروه خاصی از مجموعه داده جداسازی شود. اجازه دهید ابتدا یک جدول فراوانی براساس متغیر GoingTo بسازیم. این کار به راحتی با استفاده از دستور table امکان پذیر است. البته باید توجه داشت از آنجایی که متغیر GoingTo متغیر عامل با دو سطح محسوب میشود، جدول فراوانی کوچکی ساخته میشود. خروجی به همراه کد در زیر نشان داده شده است.
table(step_1_df$GoingTo) ## ## GSK Home ## 105 100
به این ترتیب مشاهده میشود که تعداد سفرها با مبدا خانه برابر با ۱۰0 ولی از مبدا شرکت یا محل کار ۱۰5 سفر بوده است. قرار است براساس این دو حالت دادهها را تفکیک کنیم. به کمک $$filter()$$ این کار را انجام میدهیم.
# Select observations if GoingTo == Home select_home <- filter(df, GoingTo == "Home") dim(select_home) ## [1] 100 14
به این ترتیب ۱۰۰ مشاهده برای حرکت از خانه وجود دارد. همین کار را برای حالتی که متغیر GoingTo برابر با GSK باشد نیز انجام میدهیم.
# Select observations if GoingTo == Work select_work <- filter(df, GoingTo == "GSK") dim(select_work) ## [1] 105 14
مشخص است که تعداد 105 مشاهده از این نوع وجود دارد. برای ایجاد فیلتر میتوان از ترکیب چند شرط نیز استفاده کرد. به این کار محدودیتهای چندتایی (Multiple Criteria) میگویند. برای مثال اگر به تعداد سفرهایی که با مبدا خانه و در روز چهارشنبه رخ دادهاند علاقمند هستید کافی است کد زیر را اجرا کنید.
select_home_wed <- filter(df, GoingTo == "Home" & DayOfWeek == "Wednesday") dim(select_home_wed) ## [1] 23 14
همانطور که دیده میشود، در قسمت شرط، محدودیتها بوسیله عملگر «&» به صورت ترکیب عطفی در آمدهاند. با اجرای کد مشاهده خواهید کرد که تعداد ۲۳ مورد در این گروه قرار دارند. اگر لازم باشد که محدودیتها به صورت ترکیب فصلی درآیند از عملگر «|» استفاده کنید.
عملگر سلسله مراتبی یا Pipeline
فرض کنید دستوراتی را باید اجرا کنید که خروجی یکی به عنوان ورودی دیگری باشد و به شکل سلسله مراتبی ورودیها به خروجی دستورات بعدی تبدیل شوند. با استفاده از عملگر خاصی که به صورت «%<%» نمایش داده میشود، این کار صورت میگیرد. فرض کنید کاری را باید در سه مرحله انجام دهید.
- گام ۱- خواندن اطلاعات و قرار دادن آنها در مجموعه داده Step_1
- گام ۲- انتخاب متغیرهای GoingTo و DayOfWeek از مجموعه Step_1 و قرار دادن آن در مجموعه داده Step_2
- گام ۳- اجرای فیلتر و انتخاب مشاهداتی که مبدا سفر از خانه ($$GoingTo==”Home”$$) و در روز نیز برابر با چهارشنبه ($$DayofWeek=”Wednesday”$$) باشد و ثبت آن در متغیر Step_3.
اجرای این مراحل بدون استفاده از روش سلسله مراتبی، توسط کد زیر صورت میگیرد.
# Step 1 step_1 <- read.csv(PATH) # Step 2 step_2 <- select(step_1, GoingTo, DayOfWeek) # Step 3 step_3 <- filter(step_2, GoingTo == "Home", DayOfWeek == "Wednesday") head(step_3)
حاصل اجرای این کد ایجاد خروجی به صورت زیر است. همانطور که مشاهده میکنید، روزهای چهارشنبه و مقصد خانه برای همه مشاهدات دیده میشود.
## GoingTo DayOfWeek ## 1 Home Wednesday ## 2 Home Wednesday ## 3 Home Wednesday ## 4 Home Wednesday ## 5 Home Wednesday ## 6 Home Wednesday
خوانایی و مرور کد بالا مقداری سخت است و اگر این مراحل بیشتر شوند، عملا دنبال کردن کد کار سختی خواهد شد. استفاده از عملگر Pipeline یا «%<%» کارها را سادهتر میکند. شکل استفاده از عملگر Pipeline در ادامه مشخص شده است. همانطور که دیده میشود، خروجی هر گامهای بالایی به عنوان ورودی گامهایی پایین قرار میگیرد. نتیجه اجرای این مراحل نیز در اولین سطر با نام New_df ثبت خواهد شد.
New_df <- df %>% step 1 %>% step 2 %>% ... arguments - New_df: Name of the new data frame - df: Data frame used to compute the step - step: Instruction for each step - Note: The last instruction does not need the pipe operator `%`, you don't have instructions to pipe anymore Note: Create a new variable is optional. If not included, the output will be displayed in the console.
حال با توجه به کد قبلی، عملیات را به استفاده از «%<%» انجام میدهیم. قرار است نتیجه سفرهای مربوط به مقصد خانه در روزهای چهارشنبه را در متغیر filter_home_wed ثبت کنیم.
# Create the data frame filter_home_wed.It will be the object return at the end of the pipeline filter_home_wed <- #Step 1 read.csv(PATH) % > % #Step 2 select(GoingTo, DayOfWeek) % > % #Step 3 filter(GoingTo == "Home",DayOfWeek == "Wednesday")
به طور وضوح دیده میشود که چگونه خروجی یک دستور از بالا به پایین به صورت یک روند سلسله مراتبی مورد استفاده قرار گرفته است. همچنین متغیر مشخص شده در سطر اول به نام filter_home_wed نتیجه نهایی را در خود ثبت کرده است. برای اطمینان از یکسان بودن نتیجه هر دو کد از تابع identical استفاده خواهیم کرد. با اجرای این کد وضعیت یکسان بودن مقدارهای step_3 و filter_home_wed مورد بررسی قرار میگیرد.
identical(step_3, filter_home_wed) ## [1] TRUE
مقدار TRUEنشان دهنده یکسان بودن هر دو چارچوب داده است.
استفاده از $$arrange()$$
اگر میخواهید نحوه نمایش دادهها دارای ترتیب خاصی باشند، از $$arrange()$$ استفاده کنید. شکل پارامترهای آن به صورت زیر است.
- `arrange(A)`: Ascending sort of variable A - `arrange(A, B)`: Ascending sort of variable A and B - `arrange(desc(A), B)`: Descending sort of variable A and ascending sort of B
- در حالت اول عمل مرتبسازی به صورت صعودی و براساس مقادیر متغیر A صورت میگیرد و سطرهای مجموعه داده را براساس این متغیر میچیند.
- سطر دوم به حالت اشاره دارد که مرتبسازی به صورت صعودی و براساس متغیرهای A و B به حفظ اولویت انجام میشود.
- در سطر سوم نیز مرتب سازی سطرها ابتدا براساس مرتبسازی نزولی (از زیاد به کم) برای متغیر و سپس با حفظ اولویت براساسا مرتب سازی صعودی با متغیر B صورت خواهد گرفت.
بنابراین اگر فرض کنیم میخواهیم مجموعه داده را براساس متغیرهای GoingTo و Distance به صورت صعودی با حفظ اولویت (یعنی ابتدا برحسب مبدا سفر و سپس براساس فاصله) مرتب کنیم از کد زیر استفاده خواهیم کرد.
# Sort by destination and distance step_2_df <-step_1_df %>% arrange(GoingTo, Distance) head<step_2_df)
خروجی به صورت زیر در خواهد آمد.
## X Date StartTime DayOfWeek GoingTo Distance MaxSpeed AvgSpeed ## 1 193 7/25/2011 08:06 Monday GSK 48.32 121.2 63.4 ## 2 196 7/21/2011 07:59 Thursday GSK 48.35 129.3 81.5 ## 3 198 7/20/2011 08:24 Wednesday GSK 48.50 125.8 75.7 ## 4 189 7/27/2011 08:15 Wednesday GSK 48.82 124.5 70.4 ## 5 95 10/11/2011 08:25 Tuesday GSK 48.94 130.8 85.7 ## 6 171 8/10/2011 08:13 Wednesday GSK 48.98 124.8 72.8 ## AvgMovingSpeed FuelEconomy TotalTime MovingTime Take407All ## 1 78.4 8.45 45.7 37.0 No ## 2 89.0 8.28 35.6 32.6 Yes ## 3 87.3 7.89 38.5 33.3 Yes ## 4 77.8 8.45 41.6 37.6 No ## 5 93.2 7.81 34.3 31.5 Yes ## 6 78.8 8.54 40.4 37.3 No
مشخص است که ابتدا مبدا ملاک قرار گرفته است. ابتدا سطرهایی را میبینیم که با مقدار GSK برای متغیر GoingTo هستند. این سطرها براساس متغیر فاصله یا Distance مرتب شدهاند. سپس سطرهای مربوط به مقدار Home برای متغیر GoingTo ظاهر شده که آنها هم براساس Distance و به صورت صعودی مرتب شدهاند.
نکته: ترتیب قرارگیری متغیرها در دستور $$arrange()$$ مهم است. به این معنی که اولویتها توسط ترتیب قرارگیری متغیرها در این دستور تعیین میشود. برای مثال اگر از کد دستوری زیر استفاده کنیم، ملاک اولیه برای مرتبسازی تاریخ سفر (Date) است و سپس اگر سطرهایی با تاریخ مشابه وجود داشته باشد آنگاه مرتبسازی درونی این سطرها به عهده متغیر GoingTo خواهد بود.
sorting=arrange(df,Date,desc(GoingTo)) glimpse(sorting) Observations: 205 Variables: 14 $ X <int> 7, 8, 5, 6, 3, 4, 1, 2, 94, 95, 92, 93, 91, 89, 90, 87, ... $ Date <fct> 1/2/2012, 1/2/2012, 1/3/2012, 1/3/2012, 1/4/2012, 1/4/20... $ StartTime <fct> 17:31, 07:34, 18:57, 07:57, 16:17, 07:53, 16:37, 08:20, ... $ DayOfWeek <fct> Monday, Monday, Tuesday, Tuesday, Wednesday, Wednesday, ... $ GoingTo <fct> Home, GSK, Home, GSK, Home, GSK, Home, GSK, Home, GSK, H... $ Distance <dbl> 51.37, 49.01, 51.15, 51.80, 51.27, 49.17, 51.29, 51.63, ... $ MaxSpeed <dbl> 123.2, 128.3, 136.2, 135.8, 127.4, 132.3, 127.4, 130.3, ... $ AvgSpeed <dbl> 82.9, 77.5, 83.4, 84.5, 82.0, 74.2, 78.3, 81.8, 67.3, 85... $ AvgMovingSpeed <dbl> 87.3, 85.9, 88.1, 88.8, 85.8, 82.9, 84.8, 88.9, 78.4, 93... $ FuelEconomy <fct> -, -, , , , , , , 7.81, 7.81, 8.75, 8.75, 8.75, 8.75, 8.... $ TotalTime <dbl> 37.2, 37.9, 36.8, 36.8, 37.5, 39.8, 39.3, 37.9, 46.0, 34... $ MovingTime <dbl> 35.3, 34.3, 34.8, 35.0, 35.9, 35.6, 36.3, 34.9, 39.5, 31... $ Take407All <fct> No, No, No, No, No, No, No, No, No, Yes, No, Yes, Yes, N... $ Comments <fct> , , , , , , , , , , Rain, rain, rain, Accident: backup f... >
همانطور که دیده میشود، خروجی برحسب تاریخ (Date) چیده و مرتب شده و برای تاریخهای یکسان، ترتیب قرارگیری مشاهدات توسط متغیر GoingTo صورت گرفته است.
خلاصه
جدول زیر به خلاصه مباحثی پرداخته است که به آنها در این متن اشاره شد.
دستور | هدف | کد | شرح |
glimpse | بررسی ساختار دادهها | glimpse(df) | مشابه دستور $$str()$$ |
select | انتخاب یا عدم انتخاب متغیرها | select(df, A, B ,C) | انتخاب متغیرهای A,B,C |
select(df, A:C) | انتخاب همه متغیرهای از A تا C | ||
select(df, -C) | انتخاب همه متغیرها به غیر از C | ||
filter | جداسازی مشاهدات براساس شرط | filter(df, condition1) | تعیین یک شرط |
filter(df, condition1 & condition2) | تعیین دو شرط همزمان (ترکیب عطفی) | ||
filter(df, condition1 | condition2) | تعیین دو شرط همزمان (ترکیب فصلی) | ||
arrange | مرتب سازی | arrange(A) | مرتب سازی براساس متغیر A |
arrange(A, B) | مرتب سازی براساس متغیر A و B با حفظ اولویت | ||
arrange(desc(A), B) | مرتب سازی نزولی براساس متغیر A و صعودی براساس متغیر B با حفظ اولویت | ||
%>% | سلسله مراتبی کردن عملیات | step 1 %>% step 2 %>% step 3 |
اگر مطلب بالا برای شما مفید بوده، آموزشها و مطالب زیر نیز که در زمینه به کارگیری آمار و محاسبات در نرمافزار R هستند، به شما پیشنهاد میشوند:
- مجموعه آموزشهای آمار، احتمالات و دادهکاوی
- مجموعه آموزشهای یادگیری ماشین و بازشناسی الگو
- مجموعه آموزشهای هوش محاسباتی
- آموزش برنامهنویسی R و نرمافزار R Studio
- توابع Apply در زبان برنامه نویسی R — راهنمای کاربردی
- متغیر فاکتور (Factor) یا متغیر عامل در R — راهنمای کاربردی
- توابع جمع بندی و گروه بندی (Summarise, Group_by) در R — راهنمای کاربردی
^^