حلقه تکرار (Loop) در زبان برنامه نویسی R — راهنمای کاربردی
زمانی که بخواهیم عملی تکراری در الگوریتمها را در یک زبان برنامه نویسی طراحی کنیم از حلقه تکرار (Loop) استفاده میکنیم. به این ترتیب به نظر میرسد که دستورات مربوط به ایجاد حلقههای تکرار، بسیار مهم و کاربردی هستند. برای محاسبات و برنامهنویسی الگوریتمهای «یادگیری ماشین» (Machine Learning) آگاهی و آشنایی با حلقههای تکرار بخصوص حلقه For و While ضروری است.
در بحث یادگیری ماشین، بعد از ایجاد مدل به کمک «دادههای آموزشی» (Training Data)، لازم است که به منظور بهینه کردن مدل و مقابله با بیشبرازش یا کمبرازش، مدل را به بوته آزمایش گذاشت. در چنین مواقعی با استفاده از حلقههای تکرار مدل را برای همه «دادههای آزمایشی» (Test Data) به کار برده و خطا را اندازهگیری میکنند.
در این نوشتار به بررسی دو نوع حلقه که بیشتر کاربرد دارند میپردازیم. ابتدا حلقههای for و سپس while در زبان برنامه نویسی R مورد بررسی قرار میدهیم.
حلقه (Loop) در R
به منظور ایجاد حلقه تکرار معمولا از دو روش استفاده میشود. روش شمارش تعداد تکرارها و روش تکرار شرطی. البته هر یک از این حلقهها ممکن است در زمان خاصی موثرتر و بهتر عمل کنند.
روش شمارش تعداد تکرار (For Loop): در روش شمارش تکرارها (For Loop) از یک متغیر به عنوان شمارنده استفاده شده، و با هر بار اجرای دستورات درون حلقه، مقدار شمارنده به طور خودکار یک واحد افزایش (کاهش) مییابد. معمولا زمانی که تعداد تکرار مشخص است، این نوع حلقه به کار میرود.
روش تکرار شرطی (While Loop): در این روش براساس شرطی که در حلقه تکرار وجود دارد عملیات انجام شده و در هر بار تکرار صحت ورود به حلقه تکرار بررسی میشود. بنابراین هرگاه که شرایط اجرای حلقه وجود نداشته باشد، برنامه از حلقه خارج خواهد شد. در نتیجه زمانی که تعداد تکرارها مشخص نیست و برای خاتمه عملیات تکراری نیاز به یک شرط است، حلقه تکرار شرطی While کاربرد خواهد داشت.
حلقه با روش تعداد تکرار (For Loop)
برای مشاهده نحوه عملکرد حلقه تکرار For به نمودار چرخشی زیر توجه کنید.
شکل دستوری یک حلقه تکرار شمارشی با For در زبان برنامه نویسی R به صورت زیر است.
1For (i in vector) {
2 Exp
3}
در اینجا i متغیر شمارنده است که دامنه مقدارهای آن درون بردار vector نوشته شده است. Exp نیز بیانگر محاسبات و عبارتهایی است که باید درون حلقه تکرار اجرا شوند. مشخص است که این قسمتها درون علامتهای } و { قرار گرفتهاند.
مثال ۱
فرض کنید قرار است مقدارهایی از یک بردار به صورت دنبالهای چاپ شوند. این کار را بوسیله حلقه تکرار For به شکل زیر مینویسیم.
1# Create fruit vector
2fruit <- c('Apple', 'Orange', 'Passion fruit', 'Banana')
3# Create the for statement
4for ( i in fruit){
5 print(i)
6}
از آنجایی که در متغیر fruit اسامی ۴ میوه نوشته شده است، حلقه تکرار نیز چهار بار تکرار شده و در هر بار اسامی یکی از میوه چاپ میشود.
1## [1] "Apple"
2## [1] "Orange"
3## [1] "Passion fruit"
4## [1] "Banana"
مثال ۲
در کد زیر، برای ایجاد اعداد مربع کامل از ۱ تا ۴ از حلقه تکرار For استفاده کردهایم. به این ترتیب مقدارهای ۱ تا ۴ را در خودش ضرب کرده و در یک لیست قرار دادهایم.
1# Create an empty list
2list <- c()
3# Create a for statement to populate the list
4for (i in seq(1, 4, by=1)) {
5 list[[i]] <- i*i
6}
7print(list)
مشخص است که برای ایجاد برداری از مقدارها، در حلقه از دستور seq استفاده شده تا دنباله اعداد ۱ تا ۴ ساخته شود. پس از اجرای این برنامه، خروجی مربع اعداد ۱ تا ۴ خواهد بود.
1## [1] 1 4 9 16
توجه داشته باشید که ممکن است شمارنده به جای افزایش، کاهش یابد. برای مثال اگر کد بالا را تغییر دهیم، میتوان حلقه را به صورت کاهشی نوشت.
1# Create an empty array
2ii=rep(0,4)
3# Create a for statement to populate the list
4for (i in seq(4, 1, by=-1)) {
5 ii[i] <- i*i
6print(paste('ii = ',ii[i],', i is: ', i))
7}
به این ترتیب شمارنده i دنبالهای از مقدارهای ۴ تا ۱ خواهد بود و در هر بار اجرای حلقه، مقدار آن یک واحد کاهش خواهد یافت. خروجی به صورت زیر ظاهر خواهد شد.
11] "ii = 16 , i is: 4"
2[1] "ii = 9 , i is: 3"
3[1] "ii = 4 , i is: 2"
4[1] "ii = 1 , i is: 1"
5>
استفاده از لیست در حلقه for
فرض کنید لیستی از اقلام مختلف دارید و میخواهید براساس آن یک حلقه تکرار با for بسازید. به عنوان مجموعه مقدارهای متغیر شمارنده از یک لیست نیز میتوانید استفاده کنید. مثال زیر به این موضوع پرداخته است. ابتدا لیستی از انواع میوه ایجاد شده که در انتهای آن اعداد و حتی یک مقدار منطقی اضافه شده است. حلقه تکرار براساس تعداد اعضای این لیست، اجرا شده و هر عضو را چاپ میکند.
1# Create a list with three vectors
2fruit <- list(Basket = c('Apple', 'Orange', 'Passion fruit', 'Banana'),
3Money = c(10, 12, 15), purchase = FALSE)
4for (p in fruit)
5{
6 print(p)
7}
به این ترتیب نتیجه لیستی است که هر سه نوع ورودی را شامل میشود.
1## [1] "Apple" "Orange" "Passion fruit" "Banana"
2## [1] 10 12 15
3## [1] FALSE
مشخص است که خروجی یک لیست است. به شماره سطرها توجه کنید. هر سطر مشخصات یکی از اجزای لیست را نمایش داده است.
استفاده از ماتریس در حلقه تکرار For
ماتریس شکلی از نمایش اقلام اطلاعاتی در دو بعد است. به این ترتیب، یک ماتریس دارای درایهها یا مولفههایی در سطر و همچنین در ستون است. برای نمایش اجزای یک ماتریس باید حلقههای تو در تو استفاده کنیم. به کارگیری ماتریس در یک حلقه تکرار for را به کمک مثال زیر بررسی میکنیم.
فرض کنید ماتریسی با ۶ سطر و ۲ ستون داریم. در نتیجه تعداد درایههای این ماتریس برابر با ۱۲ است. این درایهها با اعداد ۱۰ تا ۲۰ به صورت سطری پر شدهاند. البته چون ۱۱ عدد در بازه ۱۰ تا ۲۰ وجود دارد، به منظور کامل شدن ماتریس، برنامه R مقدارهای این دنباله را از اول تکرار میکند تا مشکلی در تشکیل ماتریس بوجود نیاید. این ماتریس در متغیر mat ثبت میشود.
1# Create a matrix
2mat <- matrix(data = seq(10, 20, by=1), nrow = 6, ncol =2)
3# Create the loop with r and c to iterate over the matrix
4for (r in 1:nrow(mat))
5 for (c in 1:ncol(mat))
6 print(paste("Row", r, "and column",c, "have values of", mat[r,c]))
7# Show mat matrix
8mat
همانطور که مشخص است متغیر شمارنده در حلقه اولیه r است که از ۱ تا تعداد سطرهای ماتریس mat مقدار دهی میشود. همچنین حلقه تکرار دومی که درون حلقه اول نوشته شده نیز از ۱ تا تعداد ستونها ماتریس تکرار میشود. نتیجه اجرای این کد، نمایش درایههای سطرها و ستونهای ماتریس mat است.
1[1] "Row 1 and column 1 have values of 10"
2[1] "Row 1 and column 2 have values of 16"
3[1] "Row 2 and column 1 have values of 11"
4[1] "Row 2 and column 2 have values of 17"
5[1] "Row 3 and column 1 have values of 12"
6[1] "Row 3 and column 2 have values of 18"
7[1] "Row 4 and column 1 have values of 13"
8[1] "Row 4 and column 2 have values of 19"
9[1] "Row 5 and column 1 have values of 14"
10[1] "Row 5 and column 2 have values of 20"
11[1] "Row 6 and column 1 have values of 15"
12[1] "Row 6 and column 2 have values of 10"
13> mat
14 [,1] [,2]
15[1,] 10 16
16[2,] 11 17
17[3,] 12 18
18[4,] 13 19
19[5,] 14 20
20[6,] 15 10
21>
نکته: ممکن است که مقدار آغازین برای حلقه داخلی از حلقه خارجی استخراج شود. برای مثال اگر در یک ماتریس 3 در ۳ با مقدارهای ۱ تا ۹ کد زیر را اجرا کنیم، فقط درایههای مثلث بالایی ماتریس ظاهر خواهند شد.
1mymat = matrix(data=1:9,nrow=3)
2mymat
3for (r in 1:nrow(mymat))
4 for (c in r:ncol(mymat))
5 print(paste("Row", r, "and column",c, "have values of", mymat[r,c]))
6print(mymat)
با توجه به اینکه فقط خط بعد از دستور for باید در حلقه تکرار شود، دیگر از علامت «}» و «{» استفاده نشده است. با اجرای این برنامه، خروجی به صورت زیر در خواهد آمد.
1[1] "Row 1 and column 1 have values of 1"
2[1] "Row 1 and column 2 have values of 4"
3[1] "Row 1 and column 3 have values of 7"
4[1] "Row 2 and column 2 have values of 5"
5[1] "Row 2 and column 3 have values of 8"
6[1] "Row 3 and column 3 have values of 9"
7
8 [,1] [,2] [,3]
9[1,] 1 4 7
10[2,] 2 5 8
11[3,] 3 6 9
حلقه تکرار با روش تکرار شرطی (While Loop)
اگر یک حلقه تکرار براساس While ایجاد کنید، تا زمانی که شرطی محقق شود، تکرار حلقه صورت خواهد گرفت. به این ترتیب میتوان نمودار گردشی (Flow Chart) زیر را برای حلقه While در نظر گرفت.
شکل دستوری برای حلقه شرطی While به صورت زیر است.
1while (condition) {
2 Exp
3}
نکته: توجه داشته باشید که شرطی که در قسمت condition در نظر میگیرید، با تکرار حلقه و اجرای محاسبات در بخش Exp، به حالتی برسد که مقدار شرط نادرست (False) شود. در غیراینصورت حلقه تا ابد اجرا شده و برنامه هیچگاه از حلقه خارج نخواهد شد. در ادامه به کمک یک مثال ساده، مفهوم حلقه شرطی را بررسی میکنیم.
مثال ۳
فرض کنید در هر بار تکرار حلقه ۱ واحد به متغیری به نام اضافه میشود. زمانی که این مقدار متغیر از ۱۰ بیشتر شود، از حلقه خارج خواهیم شد.
1#Create a variable with value 1
2begin <- 1
3
4#Create the loop
5while (begin <= 10){
6
7 #add 1 to the variable begin after each loop
8 begin <- begin+1
9 print(begin)
10}
به منظور مشخص کردن مقدار متغیر در هر بار تکرار حلقه، دستور را درون حلقه while قرار دادهایم. مشخص است که بخش محاسباتی حلقه While بین دو علامت «{» و «}» قرار گرفته است. خروجی این دستورات به صورت زیر است.
1[1] 2
2[1] 3
3[1] 4
4[1] 5
5[1] 6
6[1] 7
7[1] 8
8[1] 9
9[1] 10
10[1] 11
11>
نکته: همانطور که دیده میشود، برنامه، زمانی که متغیر به مقدار ۱۱ میرسد از حلقه شرطی While خارج میشود. در حالیکه در حلقه For مقدار متغیر شمارنده هرگز از تعداد تکرار مشخص شده فراتر نمیرود.
مثال ۴
فرض کنید سهمی را به قیمت ۵۰ دلار در بورس خریداری کردهاید. استراتژی خرید و فروش این سهم را به صورتی در نظر گرفتهاید که اگر قیمت به زیر ۴۵ دلار برسد، سهام را بفروشید و در غیر اینصورت سهام را نگه خواهید داشت. ارزش سهام به صورت تصادفی بین ۱۰+ تا ۱۰- دلار نسبت به قیمت فروش روز قبل نوسان دارد. در هر بار حلقه تکرار، یک نوسان تصادفی به قیمت سهام روز قبل اعمال میشود. هرگاه ارزش سهام کمتر از ۴۵ شود، برنامه از حلقه خارج میشود زیرا در این زمان شما سهام را فروختهاید. کد چنین برنامهای به صورت زیر نوشته شده است.
1set.seed(123)
2# Set variable stock and price
3stock=price <- 50
4
5
6# Loop variable counts the number of loops
7loop <- 1
8
9# Set the while statement
10while (price > 45){
11
12 # Print the number of loop
13 print(paste('loop:',loop, ' price: ',price))
14
15 # Create a random price between 40 and 60
16 price <- price + sample(-10:10, 1)
17 # Count the number of loop
18 loop = loop +1
19
20 }
21print(paste('loop:',loop, ' price: ',price))
در بخش اول دستور باعث میشود که اعداد تصادفی تولید شده در هر بار تکرار یکسان باشد. در نتیجه هر بار برنامه را اجرا کنید نتایج یکسانی خواهید گرفت. متغیر stock ارزش سهام و price نیز قیمت فروش سهام را تعیین میکند.
در بخش حلقه شرطی while قید یا شرطی که برای اجرای حلقه گذاشته شده عبارت است. به این معنی که هر گاه قیمت فروش سهام بیشتر از ۴۵ باشد، تکرار حلقه انجام میشود. در قسمت محاسبات، با دستور یک عدد تصادفی در فاصله ۱۰ تا ۱۰- تولید شده و با قیمت قبلی سهام جمع میگردد. خروجی در این حالت به صورت زیر خواهد بود.
1[1] "loop: 1 price: 50"
2[1] "loop: 2 price: 46"
3[1] "loop: 3 price: 52"
4[1] "loop: 4 price: 50"
5[1] "loop: 5 price: 58"
6[1] "loop: 6 price: 67"
7[1] "loop: 7 price: 57"
8[1] "loop: 8 price: 58"
9[1] "loop: 9 price: 66"
10[1] "loop: 10 price: 67"
11[1] "loop: 11 price: 66"
12[1] "loop: 12 price: 76"
13[1] "loop: 13 price: 75"
14[1] "loop: 14 price: 79"
15[1] "loop: 15 price: 81"
16......
17[1] "loop: 50 price: 61"
18[1] "loop: 51 price: 69"
19[1] "loop: 52 price: 59"
20[1] "loop: 53 price: 58"
21[1] "loop: 54 price: 64"
22[1] "loop: 55 price: 56"
23[1] "loop: 56 price: 57"
24[1] "loop: 57 price: 51"
25
26> print(paste('loop:',loop, ' price: ',price))
27[1] "loop: 58 price: 43"
28>
در نتیجه با ۵8 بار معامله این سهام در نهایت به فروش این سهام دست خواهید زد.
اگر مطلب بالا برای شما مفید بوده، آموزشها و مطالب زیر نیز که در زمینه به کارگیری آمار و محاسبات در نرمافزار R هستند، به شما پیشنهاد میشوند:
- مجموعه آموزشهای آمار، احتمالات و دادهکاوی
- مجموعه آموزشهای یادگیری ماشین و بازشناسی الگو
- مجموعه آموزشهای هوش محاسباتی
- آموزش برنامهنویسی R و نرمافزار R Studio
- آموزش تکمیلی برنامهنویسی R و نرمافزار RStudio
- توابع Apply در زبان برنامه نویسی R — راهنمای کاربردی
- ضریب همبستگی و ماتریس همبستگی در R — کاربرد در یادگیری ماشین
^^