R هي لغة وجوه المنحى. في ذلك ، كل شيء على الإطلاق كائن ، يبدأ من الوظائف وينتهي بالجداول.
بدوره ، كل كائن في R ينتمي إلى فئة. في الواقع ، في العالم من حولنا ، فإن الوضع هو نفسه تقريبا. نحن محاطون بالكائنات ، ويمكن أن يعزى كل كائن إلى فئة. تحدد الفئة مجموعة الخصائص والإجراءات التي يمكن تنفيذها مع هذا الكائن.

على سبيل المثال ، في أي مطبخ يوجد طاولة وموقد. وطاولة المطبخ والموقد يمكن أن يسمى معدات المطبخ. خصائص الجدول ، كقاعدة عامة ، مقيدة بأبعادها ولونها ومادتها. الموقد لديه مجموعة واسعة من الخصائص ، على الأقل الطاقة ، وعدد الشعلات ونوع الموقد (كهربائي أو غاز) سيكون إلزاميًا.
تسمى الإجراءات التي يمكن تنفيذها على الكائنات أساليبها. بالنسبة للجدول واللوحة ، على التوالي ، ستكون مجموعة الطرق مختلفة أيضًا. يمكنك تناول العشاء على الطاولة ، ويمكنك الطهي عليه ، لكن من المستحيل معالجة الأطعمة التي تستخدم فرنًا عادةً.

محتوى
خصائص الصف
في R ، ينتمي كل كائن أيضًا إلى فئة. اعتمادًا على الفصل الدراسي ، يحتوي على مجموعة معينة من الخصائص والأساليب. فيما يتعلق بالبرمجة الموجهة للكائنات (OOP) ، فإن إمكانية الجمع بين التشابه في مجموعة من الخصائص وطرق الكائنات في مجموعات (الفئات) تسمى التغليف .
المتجه هو أبسط فئة من الكائنات في R ؛ له خاصية الطول. على سبيل المثال ، سوف نأخذ حروف المتجه المدمجة.
length(letters)
[1] 26
باستخدام وظيفة length
، حصلنا على طول متجه الحروف . الآن دعونا نحاول تطبيق نفس الوظيفة على إطار التاريخ المدمج في القزحية .
length(iris)
[1] 5
دالة length
، المطبقة على الجداول ، تُرجع عدد الأعمدة.
الجداول أيضا خاصية أخرى ، البعد.
dim(iris)
[1] 150 5
تعرض الدالة dim
في المثال أعلاه معلومات تفيد بوجود 150 صفًا و 5 أعمدة في جدول القزحية .
في المقابل ، فإن المتجه ليس له بعد.
dim(letters)
NULL
وبالتالي ، تأكدنا من أن كائنات الفئات المختلفة لها مجموعة مختلفة من الخصائص.
وظائف معممة
لدى R العديد من الوظائف العامة: print
، plot
، summary
، إلخ. تعمل هذه الوظائف بشكل مختلف مع كائنات من فئات مختلفة.
خذ ، على سبيل المثال ، وظيفة plot
. دعونا تشغيله عن طريق تمرير طاولة القزحية كحجة رئيسية.
plot(iris)
النتيجة:

الآن ، دعونا نحاول أن نمر إلى دالة الرسم متجه من 100 رقم عشوائي له توزيع طبيعي.
plot(rnorm(100, 50, 30))
النتيجة:

حصلنا على رسومات بيانية مختلفة ، في الحالة الأولى ، مصفوفة الارتباط ، في الحالة الثانية ، مؤامرة الانتثار ، التي يعرض عليها مؤشر الملاحظة على طول المحور س ، وقيمته على طول المحور ص.
وبالتالي ، يمكن أن تتكيف وظيفة plot
للعمل مع فئات مختلفة. إذا عدنا إلى مصطلحات OOP ، فإن القدرة على تحديد فئة كائن وارد وتنفيذ إجراءات مختلفة مع كائنات من فئات مختلفة تسمى تعدد الأشكال . هذا يرجع إلى حقيقة أن هذه الوظيفة هي مجرد غلاف لمجموعة متنوعة من الأساليب المكتوبة للعمل مع فئات مختلفة. يمكنك التحقق من ذلك باستخدام الأمر التالي:
body(plot)
UseMethod("plot")
يطبع أمر body
نص الوظيفة إلى وحدة التحكم R. كما ترون ، يتكون جسم وظيفة الجسم من UseMethod("plot")
واحد فقط.
أي وظيفة plot
، تبدأ فقط إحدى الطرق العديدة المكتوبة لها ، اعتمادًا على فئة الكائن الذي تم تمريره إليها. عرض قائمة بجميع طرقها على النحو التالي.
methods(plot)
[1] plot.acf* plot.data.frame* plot.decomposed.ts* [4] plot.default plot.dendrogram* plot.density* [7] plot.ecdf plot.factor* plot.formula* [10] plot.function plot.hclust* plot.histogram* [13] plot.HoltWinters* plot.isoreg* plot.lm* [16] plot.medpolish* plot.mlm* plot.ppr* [19] plot.prcomp* plot.princomp* plot.profile.nls* [22] plot.raster* plot.spec* plot.stepfun [25] plot.stl* plot.table* plot.ts [28] plot.tskernel* plot.TukeyHSD*
تشير النتيجة إلى أن وظيفة الرسم لديها 29 طريقة ، من بينها plot.default ، والتي تعمل بشكل افتراضي إذا كانت الوظيفة تستقبل كائنًا من فئة غير معروفة إلى الإدخال.
باستخدام وظيفة methods
، يمكنك أيضًا الحصول على مجموعة من جميع الوظائف المعممة التي لديها طريقة مكتوبة لأي فئة.
methods(, "data.frame")
[1] $<- [ [[ [[<- [5] [<- aggregate anyDuplicated as.data.frame [9] as.list as.matrix by cbind [13] coerce dim dimnames dimnames<- [17] droplevels duplicated edit format [21] formula head initialize is.na [25] Math merge na.exclude na.omit [29] Ops plot print prompt [33] rbind row.names row.names<- rowsum [37] show slotsFromS3 split split<- [41] stack str subset summary [45] Summary t tail transform [49] type.convert unique unstack within
ما هي فئة S3 وكيفية إنشاء الفصل الخاص بك
هناك عدد من الفصول في R والتي يمكنك إنشاؤها بنفسك. واحدة من الأكثر شعبية هو S3.
هذه الفئة هي قائمة يتم فيها تخزين خصائص متنوعة للفئة التي قمت بإنشائها. لإنشاء فصلك الخاص ، ما عليك سوى إنشاء قائمة ومنحها اسمًا للفصل الدراسي.
يقدم كتاب "Art of Programming in R" مثالاً على فئة الموظف ، الذي يخزن معلومات عن الموظف. كمثال على هذه المقالة ، قررت أيضًا أخذ كائن لتخزين معلومات حول الموظفين. ولكن جعلها أكثر تعقيدًا ووظيفية.
# employee1 <- list(name = "Oleg", surname = "Petrov", salary = 1500, salary_datetime = Sys.Date(), previous_sallary = NULL, update = Sys.time()) # class(employee1) <- "emp"
وبالتالي ، أنشأنا فصلنا الخاص ، الذي يخزن البيانات التالية في هيكلها:
- اسم الموظف
- اللقب الموظف
- راتب
- الوقت الذي تم فيه تحديد الراتب
- الراتب السابق
- تاريخ ووقت آخر تحديث للمعلومات
بعد ذلك ، باستخدام الأمر class(employee1) <- "emp"
نقوم بتعيين الأمر emp إلى الكائن.
لراحة إنشاء كائنات من الفئة emp ، يمكنك كتابة وظيفة.
رمز الوظيفة لإنشاء كائنات فئة emp # create_employee <- function(name, surname, salary, salary_datetime = Sys.Date(), update = Sys.time()) { out <- list(name = name, surname = surname, salary = salary, salary_datetime = salary_datetime, previous_sallary = NULL, update = update) class(out) <- "emp" return(out) } # emp create_employee employee1 <- create_employee("Oleg", "Petrov", 1500) # class(employee1)
[1] "emp"
وظائف التعيين إلى فئات S3 المخصصة
لذلك ، أنشأنا إمبراطوريتنا الخاصة ، لكن حتى الآن لم يعطنا هذا شيئًا. دعونا نرى لماذا أنشأنا صفنا الخاص وماذا يمكننا أن نفعل به.
بادئ ذي بدء ، يمكنك كتابة وظائف التعيين للفئة التي تم إنشاؤها.
وظيفة التعيين لـ [ "[<-.emp" <- function(x, i, value) { if ( i == "salary" || i == 3 ) { cat(x$name, x$surname, "has changed salary from", x$salary, "to", value) x$previous_sallary <- x$salary x$salary <- value x$salary_datetime <- Sys.Date() x$update <- Sys.time() } else { cat( "You can`t change anything except salary" ) } return(x) }
وظيفة التعيين لـ [[ "[[<-.emp" <- function(x, i, value) { if ( i == "salary" || i == 3 ) { cat(x$name, x$surname, "has changed salary from", x$salary, "to", value) x$previous_sallary <- x$salary x$salary <- value x$salary_datetime <- Sys.Date() x$update <- Sys.time() } else { cat( "You can`t change anything except salary" ) } return(x) }
يشار دائمًا إلى وظائف التعيين عند الإنشاء بعلامات اقتباس وتبدو كما يلي: "[<-. " / "[[<-. "
. ولهم 3 الحجج المطلوبة.
- x - الكائن الذي سيتم تعيين القيمة له ؛
- i - اسم / فهرس عنصر الكائن (الاسم ، اللقب ، الراتب ، الراتب ، التاريخ ، العدد السابق ، التحديث) ؛
- القيمة - القيمة المعينة.
علاوة على ذلك في نص الوظيفة ، تكتب كيف يجب أن تتغير عناصر فصلك. في حالتي ، أريد أن يكون المستخدم قادرًا على تغيير الراتب فقط (عنصر الراتب ، والذي يكون فهرسه 3) . لذلك ، داخل الوظيفة ، أكتب if ( i == "salary" || i == 3 )
تحقق if ( i == "salary" || i == 3 )
. إذا حاول المستخدم تعديل خصائص أخرى ، فسيتلقى رسالة "You can't change anything except salary"
.
عند تغيير عنصر الراتب ، يتم عرض رسالة تحتوي على اسم الموظف ولقبه ، ومستوى راتبه الحالي والجديد. يتم تمرير الراتب الحالي إلى خاصية_السابق السابق ، ويتم تعيين الراتب قيمة جديدة. يتم أيضًا تحديث قيم salary_datetime وخصائص التحديث .
الآن يمكنك محاولة تغيير الراتب.
employee1["salary"] <- 1750
Oleg Petrov has changed salary from 1500 to 1750
تطوير طرق مخصصة للوظائف العامة
في وقت سابق ، تعلمت بالفعل أن هناك في R وظائف معممة تعمل على تغيير سلوكها وفقًا للفئة المستلمة عند إدخال الكائن.
يمكنك إضافة أساليبك إلى الوظائف المعممة الحالية وحتى إنشاء الوظائف المعممة الخاصة بك.
إحدى الوظائف العامة الأكثر شيوعًا هي print
. يتم تشغيل هذه الوظيفة في كل مرة تقوم فيها باستدعاء كائن باسمه. الآن يبدو ناتج الطباعة لكائن الفئة emp الذي أنشأناه :
$name [1] "Oleg" $surname [1] "Petrov" $salary [1] 1750 $salary_datetime [1] "2019-05-29" $previous_sallary [1] 1500 $update [1] "2019-05-29 11:13:25 EEST"
دعنا نكتب طريقتنا لوظيفة الطباعة.
print.emp <- function(x) { cat("Name:", x$name, x$surname, "\n", "Current salary:", x$salary, "\n", "Days from last udpate:", Sys.Date() - x$salary_datetime, "\n", "Previous salary:", x$previous_sallary) }
الآن يمكن أن تقوم وظيفة الطباعة بطباعة كائنات من فئة emp لدينا. ما عليك سوى إدخال اسم الكائن في وحدة التحكم والحصول على الإخراج التالي.
employee1
Name: Oleg Petrov Current salary: 1750 Days from last udpate: 0 Previous salary: 1500
خلق وظائف عامة وأساليب
تبدو معظم الوظائف العامة في الداخل متشابهة واستخدم وظيفة UseMethod
فقط.
# get_salary <- function(x, ...) { UseMethod("get_salary") }
سنقوم الآن بكتابة طريقتين لهما ، واحدة للعمل مع كائنات من فئة emp ، وسيتم إطلاق الطريقة الثانية افتراضيًا لكائنات جميع الفئات الأخرى ، للعمل الذي لا تتضمن فيه الوظيفة المعممة لدينا طريقة مكتوبة بشكل منفصل.
# emp get_salary.emp <- function(x) x$salary # get_salary.default <- function(x) cat("Work only with emp class objects")
يتكون اسم الطريقة من اسم الوظيفة وفئة الكائنات التي ستعمل عليها هذه الطريقة. سيتم تشغيل الطريقة الافتراضية في كل مرة تقوم فيها بتمرير كائن فئة لا تتم كتابة الطريقة إليه.
get_salary(employee1)
[1] 1750
get_salary(iris)
Work only with emp class objects
ميراث
مصطلح آخر سوف تصادفه عند تعلم البرمجة الموجهة للكائنات.

يمكن تصنيف كل ما يظهر في الصورة كفئة نقل . في الواقع ، كل هذه الأشياء لها طريقة شائعة - الحركة ، والخصائص المشتركة ، على سبيل المثال ، السرعة. ومع ذلك ، يمكن تقسيم جميع الكائنات الستة إلى ثلاث فئات فرعية: الأرض والماء والهواء. في هذه الحالة ، سترث الفئة الفرعية خصائص الفئة الأصل ، ولكن سيكون لها أيضًا خصائص وطرق إضافية. خاصية مماثلة في إطار البرمجة الموجهة للكائنات تسمى الميراث .
في مثالنا ، يمكننا تخصيص عمال عن بعد لفئة فرعية منفصلة من remote_emp . سيكون لهؤلاء الموظفين خاصية إضافية: مدينة الإقامة.
# employee2 <- list(name = "Ivan", surname = "Ivanov", salary = 500, salary_datetime = Sys.Date(), previous_sallary = NULL, update = Sys.time(), city = "Moscow") # remote_emp class(employee2) <- c("remote_emp", "emp") # class(employee2)
[1] "remote_emp" "emp"
عند تعيين فئة ، وإنشاء فئة فرعية ، نستخدم متجهًا يكون فيه العنصر الأول هو اسم الفئة الفرعية ، متبوعًا باسم الفئة الأصل.
في حالة الميراث ، ستعمل جميع الوظائف والأساليب المعممة المكتوبة للعمل مع الفئة الأصل بشكل صحيح مع فئاتها الفرعية.
# remote_emp employee2
Name: Ivan Ivanov Current salary: 500 Days from last udpate: 0 Previous salary:
# salary remote_emp get_salary(employee2)
[1] 500
ولكن يمكنك تطوير طرق منفصلة لكل فئة فرعية.
# salary remote_emp get_salary.remote_emp <- function(x) { cat(x$surname, "remote from", x$city, "\n") return(x$salary) }
# salary remote_emp get_salary(employee2)
Ivanov remote from Moscow [1] 500
وهي تعمل على النحو التالي. أولاً ، تبحث الدالة المعممة عن طريقة مكتوبة للفئة الفرعية remote_emp ، وإذا لم تعثر عليها ، فإنها تذهب إلى أبعد من ذلك وتبحث عن طريقة مكتوبة لبرنامج emp من الفئة الأصل.
عندما يمكنك استخدام الفصول الدراسية الخاصة بك
من غير المحتمل أن تكون وظيفة إنشاء فصول S3 الخاصة بك مفيدة لأولئك الذين بدأوا للتو رحلتهم في إتقان اللغة R.
شخصيا ، جاءوا في متناول اليد في تطوير حزمة rfacebookstat . الحقيقة هي أنه في Facebook API ، توجد المعلمة action_breakdowns لتحميل الأحداث والرد على المنشورات الإعلانية في مجموعات مختلفة.
عند استخدام هذه المجموعات ، تحصل على استجابة في شكل بنية JSON بالتنسيق التالي:
{ "action_name": "like", "action_type": "post_reaction", "value": 6 } { "action_type": "comment", "value": 4 }
يختلف عدد العناصر المختلفة لعنصر الحركة والإفصاح عنها ، لذا يجب عليك كتابة محلل خاص بكل عنصر. لحل هذه المشكلة ، استخدمت وظيفة إنشاء فئات S3 مخصصة ووظيفة معممة مع مجموعة من الطرق.
عند طلب إحصائيات حول الأحداث مع المجموعات ، بناءً على قيم الوسائط ، تم تعريف فئة تم تعيينها للاستجابة المتلقاة من واجهة برمجة التطبيقات. تم تمرير الاستجابة إلى دالة عامة ، واعتمادًا على الفئة المحددة مسبقًا ، تم تحديد طريقة لتحليل النتيجة. يمكن لأي شخص مهتم بالبحث في تفاصيل التنفيذ العثور على رمز لإنشاء وظيفة معممة وطرق ، وهنا هو استخدامها.
في حالتي ، استخدمت فئات وأساليب لمعالجتها حصريًا داخل الحزمة. إذا كنت بحاجة إلى تزويد مستخدم الحزمة عمومًا بواجهة للعمل مع الفئات التي قمت بإنشائها ، فيجب تضمين جميع الطرق S3method
في ملف S3method
، على النحو التالي.
S3method(_,) S3method("[<-",emp) S3method("[[<-",emp) S3method("print",emp)
استنتاج
كما هو واضح من عنوان المقال ، هذا هو الجزء الأول فقط ، لأنه في R ، بالإضافة إلى فئات S3 ، هناك فئات أخرى: S4 ، R5 ( RC ) ، R6 . سأحاول في المستقبل الكتابة عن كل من تطبيقات OOP هذه. ومع ذلك ، فإن أي شخص لديه مستوى اللغة الإنجليزية يسمح لهم بقراءة الكتب بحرية ، ثم يعد Headley Wickham مختصراً إلى حد ما ، ومع أمثلة قام بتغطية هذا الموضوع في كتابه "Advanced R" .
إذا فاتتني فجأة في مقال بعض المعلومات المهمة حول فصول S3 ، سأكون ممتنا إذا كتبت عن ذلك في التعليقات.