بیشتر کارهایی که در زبان R انجام میدهیم، توسط توابع صورت میگیرد. تاکنون من از توابعی که بهصورت پیشفرض در R تعریفشدهاند، استفاده کردم. ولی این امکان وجود دارد که شما توابع موردنظرتان را ایجاد کنید. نوشتن توابع آغاز راهی است که شما را از استفادهکننده صرف از R به توسعهدهنده تبدیل میکند. توابع معمولاً زمانی بکار میروند که بخواهیم یک سری دستور را در کنار هم قرار داده و بارها و بارها به شکل تقریباً مشابهی استفاده کنیم.
همینطور در زمانهایی که بخواهیم کدهای خود را با دیگران به اشتراک بگذاریم، غالباً از تابع استفاده میکنیم. با استفاده از توابع توسعهدهندگان میتوانند برای کدهای خود یک رابط تعریف کنند که کاربران با تنظیم چند پارامتر آن را اجرا کنند بدون آنکه لازم باشد با کدهای پشت آن آشنا باشند. برای نمونه معمولاً در بستههایی (Packages) که توسط توسعهدهندگان ایجاد شده است، شما بهعنوان کاربر از توابع تعریفشده استفاده میکنید بدون آنکه خود را درگیر کدهای این بستهها کنید.
در این مقاله من به نحوه کدنویسی توابع در R میپردازم. رویکرد من در آموزش زبان برنامهنویسی R بیشتر مبتنی بر استفاده از مثال است تا خواننده با اجرای کدها بتواند این زبان را یاد بگیرد.
برای آشنایی با نحوه شروع به کار با زبان R به مقاله “آموزش زبان R برای علوم داده: مباحث مقدماتی” مراجعه کنید.
نوشتن تابع در R
برای نوشتن توابع در R از تابع function استفاده میشود. در کد زیر من تابع سادهای نوشتم که با فراخوانی این تابع کلمه “سلام” چاپ میشود. ابتدا لازم است برای تابع خود نامی انتخاب کنم. من این تابع را f1 نامگذاری کردم. داخل آکولاد دستورهایی را که لازم است با فراخوانی این تابع اجرا شوند، آوردم. در این مثال تنها یک دستور وجود دارد و آن چاپ کردن کلمه سلام است. در انتها تابع f1 را فراخوانی کردم و همانطور که میبینید دستور موردنظر اجرا شده است.
1 2 3 4 5 6 | > #Functions > f1 <- function() { + print("سلام") + } > f1() [1] "سلام" |
در مثال دیگر، من تابعی نوشتم که یک بردار مانند x را میگیرد و k درصد از کوچکترین و بزرگترین اعداد آن را جدا کرده و میانگین اعداد باقیمانده در بردار x را اعلام میکند. من این تابع را tmean نامگذاری میکنم که لازم دارد ورودی x و k را از کاربر دریافت کند. با استفاده از تابع پیشفرض quantile در R، دو عددی که یکی از k درصد اعداد موجود در x کوچکتراست و دیگری را که از مقدار k-1 درصد اعداد موجود در x بزرگتر است، مشخص میکنم. سپس میانگین اعداد موجود در بردار x را که بین این دو عدد قرار دارند، با استفاده از تابع mean به دست میآورم.
1 2 3 4 | > tmean <- function(x, k){ + xt <- quantile(x, c(k, 1 - k)) + mean(x[x > xt[1] & x < xt[2]]) + } |
توجه کنید میتوانید از تابع return استفاده کنید تا آنچه را که تابع قرار است بهصورت خروجی نشان دهد، برگردانید. بهصورت پیشفرض، توابع در R پس از اجرا، آخرین خط بدنه کد را بهعنوان خروجی در نظر میگیرد.
در زیر این تابع را روی بردار test که شامل ۱۰۰ عدد تصادفی که از توزیع نرمال با میانگین ۰ و انحراف معیار ۱ نمونهگیری شده است، آزمایش کردم.
1 2 3 | > test <- rnorm(100) > tmean(test, 0.05) [1] 0.02563822 |
در تعریف تابع tmean من از دو تابع موجود در R استفاده کردم. بهطور مشابه میتوانید در داخل تابعی که تعریف میکنید از توابعی که قبلاً خودتان و یا دیگران تعریف کردند، استفاده کنید.
نکته جالب دیگر اینکه اگر نام تابع را بدون پرانتز وارد کنید، میتوانید کدهای پشت آن را مشاهده کنید. این به شما کمک میکند در صورت نیاز توابعی را که دیگران نوشتند، بررسی نمایید.
1 2 3 4 5 | > tmean function(x, k){ xt <- quantile(x, c(k,1 - k)) mean(x[x > xt[1] & x < xt[2]]) } |
ذخیره کردن توابع در R
من از تابع dump استفاده کردم تا تابع tmean را ذخیره کنم. این تابع را در فایلی به نام tmean.R بر روی نشانی فضای کاری (Work Directory) ذخیره کردم. در صورت نیاز میتوانید با نرمافزارهای پردازش متنی مانند Notepad این فایل را باز و ویرایش کنید. برای فراخوانی این تابع از source استفاده کنید و پس از فراخوانی، میتوانید آن را بکار ببرید.
1 2 3 4 | > dump("tmean","tmean.R") > source("tmean.R") > tmean(test, 0.05) [1] 0.02563822 |
آرگومانها و متغیرها
ورودیهایی که تابع دریافت میکند و بر اساس آن اعمالی را انجام میدهد آرگومان نامیده میشوند. در تعریف یک تابع میتوانید روشن کنید واردکردن چه آرگومانهایی باید اجباری باشند و کدامیک اختیاری. در مثال زیر، تابع f2 دو آرگومان دارد. مقدار توان، k، بهصورت پیشفرض ۲ در نظر گرفته شده است. اگر کاربر مقدار k را ندهد، تابع با خطا مواجه نمیشود ولی واردکردن مقدار x اجباری است. ضمن اینکه کاربر میتواند هر دو آرگومان را نیز وارد کند.
1 2 3 4 5 6 7 8 9 | > f2 <- function(x, k = 2) { + x ^ k + } > f2(5) [1] 25 > f2() Error in f2() : argument "x" is missing, with no default > f2(5, 3) [1] 125 |
نکته دیگر اینکه متغیرها در داخل توابع، متغیرهای محلی (Local Variables) هستند؛ یعنی پس از اجرای تابع این متغیرها از دست میروند و کاربردشان تنها به کدهای داخل تابع محدود میشود. در مثال زیر من به متغیر x مقدار ۳ را تخصیص دادم. سپس متغیر x را در داخل تابع f3 بکار بردم و به آن مقدار صفر را تخصیص دادم. پس از اجرای تابع دوباره x را فراخوانی کردم و همانطور که میبینید، x همچنان مقدار ۳ را به خود گرفته است.
1 2 3 4 5 6 7 | > x <- 3 > f3 <- function() { + x <- 0 + } > f3() > x [1] 3 |
مفهوم ارزیابی تنبل (Lazy Evaluation) در R
ارزیابی تنبل یک رویکرد در طراحی الگوریتمهاست که بر این دیدگاه استوار است که “زمانت را برای چیزی که به آن نیاز نداری، صرف نکن.” به تابع f4 در زیر توجه کنید. با توجه به تعریف، این تابع نیازمند دو آرگومان است ولی اگر تنها یک آرگومان به آن بدهید، تابع با خطا مواجه نمیشود چراکه تابع برای اجرا به آرگومان دومی نیازی ندارد.
1 2 3 4 5 | > f4 <- function(x, y){ + 100 * x + } > f4(2) [1] 200 |
ارزیابی تنبل در R اجازه میدهد که برنامه کارآمدتر شود، تنها ورودیهایی که لازم است ارزیابی شوند و تنها اشیائی که لازم است در حافظه کامپیوتر بارگذاری شوند.
توابع و ساختارهای کنترلی (Control Structures)
این امکان وجود دارد که شما ساختارهای کنترلی را داخل توابع بکار ببرید. من در مقاله دیگری، درباره ساختارهای کنترلی مفصل بحث کردم. در اینجا تنها به یک مثال از نحوه بکار بردن حلقه داخل تابع، اکتفا میکنم.
در این مثال من مدل ریکر (Ricker’s Model) را در مدلسازی جمعیت یک گونه زیستی بکار بردم. مدل ریکر جمعیت در زمان را بر اساس جمعیت در زمان از رابطه زیر محاسبه میکند:
در رابطه بالا، نرخ رشد جمعیت، حداکثر جمعیت ممکن آن گونه زیستی با توجه به ظرفیت محیط و و به ترتیب جمعیت در زمان و است.
تابع زیر مقادیر ورودی را گرفته و نمودار تغییر جمعیت در بازه زمانی موردنظر را به نمایش میگذارد. شکل-۱ خروجی این تابع را بر اساس جمعیت اولیه ۱۰۰، نرخ رشد ۹ درصد و حداکثر ظرفیت ۱۰۰۰۰ نشان میدهد.
1 2 3 4 5 6 7 8 9 | > RModel <- function(nzero, r, k = 1, time = 100, from = 0, to = time){ + N <- numeric(time + 1) + N[1] <- nzero + for (i in 1 : time) N[i + 1] <- N[i]*exp(r * (1 - N[i] / k)) + Time <- 0 : time + plot(Time, N, type = "l", xlim = c(from, to)) + } > > RModel(100, 0.09, 10000) |
مقالات آموزش زبان R در آنالیکا
آموزش زبان R برای علوم داده: مباحث مقدماتی
آموزش زبان R برای علوم داده: خواندن و نوشتن دادهها
آموزش زبان R برای علوم داده: عبارات شرطی و حلقهها
سلام وقت بخیر، من برای پایان نامه م نیاز دارم به رسم یک شکل، کسی هست که اینکارو انجام بده و شغلش این باشه؟؟؟ ممنون میشم پاسخگو باشید