كتاب "فن البرمجة في R. الانغماس في البيانات الكبيرة"

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

بعض أمثلة القراء التي قد تستفيد من هذا الكتاب:

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


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

  • يحتوي هذا الكتاب على أقسام من "الأمثلة المتقدمة". عادةً ما توفر وظائف كاملة للأغراض العامة بدلاً من أجزاء التعليمات البرمجية المعزولة استنادًا إلى بيانات محددة. علاوة على ذلك ، قد تكون بعض هذه الوظائف مفيدة في عملك اليومي مع R. من خلال دراسة هذه الأمثلة ، لن تتعلم فقط كيفية عمل R محددة ، ولكن أيضًا تتعلم كيفية دمجها في برامج مفيدة. في كثير من الحالات ، أقدم وصفًا للحلول البديلة وأجيب على السؤال التالي: "لماذا تم ذلك بهذه الطريقة؟"
  • يتم تقديم المواد مع الأخذ في الاعتبار تصور مبرمج. على سبيل المثال ، عند وصف إطارات البيانات ، لا أدعي فقط أن إطار البيانات في R عبارة عن قائمة ، لكنني أوضح أيضًا عواقب هذه الحقيقة من وجهة نظر البرمجة. وأيضًا في النص ، تتم مقارنة R باللغات الأخرى حيث قد يكون ذلك مفيدًا (للقراء الذين يتحدثون هذه اللغات).
  • يلعب تصحيح الأخطاء دورًا مهمًا في البرمجة بأي لغة ، لكن معظم الكتب على R لا تذكر هذا الموضوع. في هذا الكتاب ، كرست فصلاً كاملاً لأدوات تصحيح الأخطاء ، واستخدمت مبدأ "الأمثلة المتقدمة" ، وقدمت عروضًا تم تطويرها بالكامل حول كيفية تصحيح البرامج في الواقع.
  • في الوقت الحاضر ، ظهرت أجهزة كمبيوتر متعددة النواة في جميع المنازل ، وتنتج برامج المعالجات الرسومية (GPUs) ثورة غير محسوسة في مجال الحوسبة العلمية. تتطلب المزيد والمزيد من تطبيقات R كميات كبيرة جدًا من الحساب ، وقد أصبحت المعالجة المتوازية ذات صلة بمبرمجي R. ويخصص فصل كامل لهذا الموضوع في الكتاب ، بالإضافة إلى وصف الميكانيكا ، يتم أيضًا تقديم أمثلة متقدمة.
  • يتحدث فصل منفصل عن كيفية استخدام معلومات حول التنفيذ الداخلي والجوانب الأخرى من R لتسريع عمل رمز R.
  • يركز أحد الفصول على واجهة R مع لغات البرمجة الأخرى مثل C و Python. مرة أخرى ، يتم توجيه اهتمام خاص إلى الأمثلة المتقدمة والتوصيات لتصحيح الأخطاء.

مقتطفات. 7.8.4. متى يجب استخدام المتغيرات العالمية؟


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

يعد استخدام المتغيرات العامة في R أكثر شيوعًا مما تتوقع. والمثير للدهشة أن R تستخدم المتغيرات العالمية على نطاق واسع جدًا في تنفيذها الداخلي (في كل من كود C ووظائف R). لذلك ، يستخدم عامل التشغيل الفائق << - في العديد من وظائف مكتبة R (على الرغم من أنه يستخدم عادة للكتابة إلى متغير يقع مستوى واحد فقط أعلى في التسلسل الهرمي للمتغيرات). عادةً ما يستخدم الكود متعدد الخيوط ورمز GPU المستخدم لكتابة البرامج السريعة (انظر الفصل 16) المتغيرات العامة التي توفر الآلية الرئيسية للتفاعل بين المنفذين المتوازيين.

الآن ، من أجل الدقة ، دعونا نعود إلى مثال سابق من القسم 7.7:

f <- function(lxxyy) { # lxxyy — ,  x  y ... lxxyy$x <- ... lxxyy$y <- ... return(lxxyy) } #  x  y lxy$x <- ... lxy$y <- ... lxy <- f(lxy) #   x  y ... <- lxy$x ... <- lxy$y 

كما ذكرنا سابقًا ، يمكن أن يصبح هذا الرمز مرهقًا ، خاصةً إذا كانت x و y هما قائمتان.

من ناحية أخرى ، ألقِ نظرة على نظام بديل باستخدام المتغيرات العالمية:

 f <- function() { ... x <<- ... y <<- ... } #  x  y x <-... y <-... f() #  x  y  #   x  y ... <- x ... <- y 

ربما تكون النسخة الثانية أكثر نظافة وأقل حجمًا ولا تتطلب معالجة قائمة. رمز واضح عادة ما يخلق مشاكل أقل في الكتابة ، وتصحيح الأخطاء ، والصيانة.

لهذه الأسباب - لتبسيط وتقليل ضخامة الكود - قررنا استخدام المتغيرات العامة بدلاً من إرجاع القوائم في كود DES المعطى مسبقًا. النظر في هذا المثال بمزيد من التفصيل.

تم استخدام متغيرين عالميين (كلاهما عبارة عن قوائم تحتوي على معلومات مختلفة): يرتبط متغير sim برمز المكتبة ، ومتغير mm1glbls مرتبط برمز التطبيق المحدد M / M / 1. لنبدأ مع sim.

حتى المبرمجون المقيدون بشأن المتغيرات العالمية يتفقون على أن استخدام هذه المتغيرات يمكن تبريره إذا كانت عالمية بالفعل - بمعنى أنها تستخدم على نطاق واسع في البرنامج. كل هذا يتعلق بمتغير sim من مثال DES: يتم استخدامه في كل من كود المكتبة (في schedevnt () ، getnextevnt () و dosim ()) وفي كود M / M / 1 (في mm1reactevnt ()). في هذا المثال بالذات ، تقتصر المكالمات اللاحقة على sim على القراءة ، ولكن التسجيل ممكن في بعض الحالات. مثال نموذجي من هذا النوع هو تنفيذ ممكن لإلغاء الحدث. على سبيل المثال ، قد يحدث مثل هذا الموقف عند نمذجة مبدأ "الأقدم من الاثنين": يتم التخطيط لحدثين ، وعندما يحدث أحدهما ، يجب إلغاء الآخر.

وبالتالي ، يبدو أن استخدام sim كمتغير عالمي له ما يبرره. ومع ذلك ، إذا رفضنا بحزم استخدام المتغيرات العالمية ، يمكن وضع sim في متغير محلي داخل dosim (). سوف تمرر هذه الوظيفة sim في وسيطة جميع الوظائف المذكورة في الفقرة السابقة (schedevnt () ، getnextevnt () ، وما إلى ذلك) ، وستُرجع كل من هذه الوظائف متغير sim المعدل.
على سبيل المثال ، السطر 94:

 reactevnt(head) 

تم التحويل إلى النموذج التالي:

 sim <- reactevnt(head) 

بعد ذلك ، يجب إضافة السطر التالي إلى وظيفة mm1reactevnt () المرتبطة بتطبيق معين:

 return(sim) 

يمكن القيام بشيء مماثل باستخدام mm1glbls من خلال تضمين متغير محلي في dosim () مع الاسم (على سبيل المثال) appvars. ولكن إذا تم ذلك باستخدام متغيرين ، فيجب وضعهما في القائمة بحيث يمكن إرجاع كلا المتغيرين من الوظيفة ، كما في المثال أعلاه من الدالة f (). ثم ينشأ الهيكل الضخم للقوائم داخل القوائم ، والتي تم ذكرها أعلاه ، أو بالأحرى ، القوائم داخل القوائم داخل القوائم.

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

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

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

بالطبع ، يمكن حل المشكلة بسهولة - يكفي اختيار أسماء طويلة للمتغيرات العامة المرتبطة بتطبيق معين. ومع ذلك ، توفر البيئات أيضًا تسوية معقولة ، كما في الحالة التالية لمثال DES.

داخل وظيفة dosim () ، الخط

 sim <<- list() 

يمكن استبداله بسلسلة

 assign("simenv",new.env(),envir=.GlobalEnv) 

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

 if (is.null(sim$evnts)) { sim$evnts <<- newevnt 

في schedevnt () تأخذ النموذج

 if (is.null(get("evnts",envir=simenv))) { assign("evnts",newevnt,envir=simenv) 

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

كالعادة ، لا يوجد نمط برمجة واحد يوفر أفضل النتائج في جميع الحالات. يعد الحل مع المتغيرات العامة خيارًا آخر يجب تضمينه في ترسانة أدوات البرمجة الخاصة بك.

7.8.5. دوائر قصيرة


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

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

 1 > counter 2 function () { 3 ctr <- 0 4 f <- function() { 5 ctr <<- ctr + 1 6 cat("this count currently has value",ctr,"\n") 7 } 8 return(f) 9 } 

دعونا نتحقق من كيفية عمل هذا الرمز قبل الغوص في تفاصيل التنفيذ:

 > c1 <- counter() > c2 <- counter() > c1 function() { ctr <<- ctr + 1 cat("this count currently has value",ctr,"\n") } <environment: 0x8d445c0> > c2 function() { ctr <<- ctr + 1 cat("this count currently has value",ctr,"\n") } <environment: 0x8d447d4> > c1() this count currently has value 1 > c1() this count currently has value 2 > c2() this count currently has value 1 > c2() this count currently has value 2 > c2() this count currently has value 3 > c1() this count currently has value 3 

هنا ، يتم استدعاء الدالة counter () مرتين ، ويتم تعيين النتائج c1 و c2. كما هو متوقع ، يتكون هذان المتغيران من وظائف ، وهي نسخ من f (). على الرغم من ذلك ، يصل f () إلى المتغير ctr عبر عامل التعيين الفائق ، وسيكون هذا المتغير متغيرًا بالاسم المحدد local to counter () ، لأنه سيكون الأول على المسار في التسلسل الهرمي للبيئة. إنها جزء من البيئة f () ، وعلى هذا النحو يتم تعبئتها في ما يعود إلى جانب استدعاء العداد (). النقطة الأساسية هي أنه مع استدعاءات مختلفة لمواجهة () ، سيكون المتغير ctr في بيئات مختلفة (في بيئة المثال ، تم تخزينه في الذاكرة على العنوانين 0x8d445c0 و 0x8d447d4). بمعنى آخر ، ستنشئ مكالمات مختلفة لمواجهة () حالات مختلفة فعليًا من ctr.

نتيجة لذلك ، تعمل الدالتان c1 () و c2 () كعدادات مستقلة تمامًا. يمكن ملاحظة ذلك من المثال الذي تُسمى فيه كل وظيفة عدة مرات.

»يمكن الاطلاع على مزيد من المعلومات حول الكتاب على موقع الناشر
» المحتويات
» مقتطفات

حسم 25٪ على كوبون للباعة المتجولين - ص

عند دفع النسخة الورقية من الكتاب ، يتم إرسال نسخة إلكترونية من الكتاب عن طريق البريد الإلكتروني.

Source: https://habr.com/ru/post/ar452746/


All Articles