اذهب إلى المحتوى

خالد الشمعة

الأعضاء
  • المساهمات

    10
  • تاريخ الانضمام

  • تاريخ آخر زيارة

  • عدد الأيام التي تصدر بها

    2

آخر يوم ربح فيه خالد الشمعة هو نوفمبر 4 2016

خالد الشمعة حاصل على أكثر محتوى إعجابًا!

11 متابعين

آخر الزوار

لوحة آخر الزوار معطلة ولن تظهر للأعضاء

إنجازات خالد الشمعة

عضو مساهم

عضو مساهم (2/3)

16

السمعة بالموقع

  1. بنية الشبكات العصبية الصنعية تتكون الشبكات العصبية الصنعية من عناصر أولية بسيطة من حيث طريقتها في معالجة البيانات تدعى العصبونات، ويمكن تمثيل أي من تلك العصبونات رياضيا -وفق مفاهيم البرمجة غرضية التوجه- على شكل كائن برمجي Object يتضمن كل نسخة (Instance) منه على مصفوفة من أوزان الدخل يساوي حجمها عدد إشارات الدخل الواردة لهذا العصبون والتي قد تتراوح ما بين العشرات والآلاف تبعا لبنية الشبكة العصبية وهيكليتها. إن معالجة العصبون الواحد للإشارات الواردة بسيطة من الناحية الرياضية، حيث يتم ضرب كل إشارة دخل بقيمة الوزن المقابل لها ومن ثم تجمع كافة النواتج لنحصل على مقدار كلي يمثل درجة استثارة العصبون أو شحنته الإجمالية، ومن ثم يرسل هذا الرقم إلى تابع التفعيل، وهو ببساطة علاقة رياضية تحاكي إلى حد ما سلوك العصبونات الحقيقية فيما يخص قانون الكل أو لاشيء مع بعض التصرف لاعتبارات تتعلق بخوارزميات التعليم المستخدمة (إمكانية حساب المشتق الرياضي كما في حالة تابع Sigmoid) أو لاعتبارات براغماتية عملية (سهولة البرمجة وسرعة التنفيذ كما في حالة التابع ReLU) أو حتى لاعتبارات تتعلق بطبيعة البيانات المعالجة (كشيوع استخدام التابع TanH عند التعامل مع بيانات الفئات والأصناف). في نهاية المطاف تستخدم قيمة الاستثارة الإجمالية للعصبون كدخل لتابع التفعيل x هذا، وبتطبيق العلاقة الرياضية الخاصة بتابع التفعيل المحدد للعصبون نحسب قيمة y المقابلة والتي تمثل الآن خرج هذا العصبون. تتألف الشبكات العصبية من بضع عشرات أو مئات أو حتى الآلاف من تلك الوحدات البنائية الأساسية والتي تنتظم في معمارية على شكل طبقات، حيث يحدد لكل طبقة عدد العصبونات التي تتضمنها، ونوع تابع التفعيل المستخدم لعصبونات تلك الطبقة (أي أن تابع التفعيل قد يختلف من طبقة إلى أخرى لكنه عادة ما يكون ذاته لجميع عصبونات الطبقة الواحدة)، وطريقة ارتباطها بالطبقة التي تسبقها والتي تليها (هل هو ربط كامل كأن تصل إشارة دخل واردة من كل عصبون موجود في الطبقة السابقة، أم هو جزئي يأخذ دخله من عصبونات الطبقة السابقة المجاورة لموضعه الحيزي كما هو حال الشبكات العصبية الصنعية التي تحاكي الباحات البصرية في الدماغ بغية التعرف على الأنماط في الصور). الفرق ما بين تدريب واستخدام الشبكات العصبية الصنعية إن تدريب الشبكات العصبية الصنعية يقصد به إيجاد القيم الأنسب لكافة أوزان الدخل لعصبونات الشبكة بحيث تكون قادرة على إعطاء الإجابات الصحيحة بأقل هامش خطأ في مخرجاتها وذلك للمدخلات المعروضة عليها، في حين يقع على عاتق المطور فن تحديد المعمارية الملائمة من حيث عدد الطبقات ونوع تابع تفعيل كل منها وعدد عصبوناته وطريقة ربطها مع بعضها البعض. قد تكون مهمة تدريب الشبكات العصبية الصنعية تحديا حسابيا هائلا تتطلب كما كبيرا من المعالجات الرياضية والتي قد تستغرق زمنا طويلا حتى لو أجريت على حواسيب فائقة، لكن بمجرد الوصول إلى الحل وإيجاد قيم الأوزان الملائمة التي تعطي نتائج مرضية عند معالجتها للبيانات، تصبح مسألة الاستخدام والتطبيق في منتهى البساطة، فكل ما عليك القيام به هو تمرير وحيد عبر طبقات الشبكة يتم خلاله إجراء بضع عمليات ضرب وجمع ومن ثم تطبيق تابع رياضي ما (تابع التفعيل)، وهكذا تمرر القيم من طبقة إلى أخرى وصولا إلى طبقة الخرج النهائية لتظهر من خلالها الإجابة. كيفية حفظ وتصدير الشبكات العصبية الصنعية بعد إتمام عملية تدريب الشبكة العصبية الصنعية والرضى عن نتائجها، كل ما نحتاج إليه هو حفظ بنيتها من حيث عدد الطبقات، وعدد العصبونات في كل طبقة، وطريقة ارتباط عصبونات الطبقات المختلفة بعضها ببعض، وكذلك تابع التفعيل المستخدم في كل طبقة، إضافة إلى قيم الأوزان لكل عصبون على حدة. هذا كل مافي الأمر! فإن حصلت على هذه الأرقام مجددا فأنت قادر على إعادة بناء واستخدام تلك الشبكة العصبية الصنعية بشكلها النهائي بعد أن اكتملت عملية تدريبها. عادة ما تقوم مكتبة TensorFlow بحفظ نموذج الشبكة العصبية الصنعية بكافة وسطائها وقيمها ضمن مجلد خاص بذلك خلال عملية التدريب والذي يمكن قراءته واستعادة بنية شبكته العصبية باستخدام لغة Python (ستجد ضمنه ملف بامتداد ‎*.pb إضافة إلى مجلدين فرعيين هما variables وassets)، لكن هذه الصيغة من الحفظ ملائمة فقط لبيئة التطوير ولا تصلح للتطبيق العملي. عوضا عن ذلك أتاحت Google مجموعة من الصيغ المعيارية المناسبة للتطبيقات المختلفة من أهمها صيغة ‎*.tfjs الموجهة للمبرمجين بلغة JavaScript ذائعة الصيت وواسعة الانتشار في عالم الويب سواء باستخدامها على طرف المستعرض أو حتى على طرف المخدم من خلال تقنية Node.js، كذلك لدينا صيغة ‎*.tflite والمصممة أصلا لتعمل بموارد محدودة من سرعة معالجة ومساحة ذاكرة وذلك بهدف استخدامها على أجهزة الجوال أو إنترنت الأشياء. لا يقتصر الأمر على ذلك فحسب، لكن حزم الشبكات العصبية الصنعية وإعدادها للاستخدام العملي قد يتضمن بعضا من المقايضة بهدف تصغير حجمها وزيادة سرعة عملها ولو كان ذلك على حساب انخفاض طفيف ومقبول في دقة نتائجها، إحدى تلك الخوارزميات على سبيل المثال تقوم بإزالة الروابط التي تقترب قيم أوزانها من الصفر باعتبارها لا تساهم بشكل كبير في مقدار الاستثارة الكلية للعصبون المرتبطة به، في المقابل نكون قد خفضنا عدد الأوزان التي نحن بحاجة إلى حفظها وكذلك قللنا الزمن الكلي اللازم للحساب كون عدد المدخلات أصبح أقل. مكتبة Face-API كما هو واضح من المقدمة السابقة، فنحن لن نقوم هنا ببناء وتدريب شبكة عصبية صنعية من الصفر، لكننا في المقابل سوف نستعرض كيفية استخدام شبكة عصبية صنعية سبق وأن تم تدريبها وذلك ضمن تطبيقنا الخاص. لهذه الغاية أود تعريفكم بمكتبة face-api.js والتي تم بناؤها لأغراض التعرف على الوجوه وتمييزها ضمن بيئة المتصفح إنطلاقا من مكتبة TensorFlow.js، وهي بذلك تقدم مجموعة من نماذج الشبكات العصبية الصنعية المدربة والجاهزة لطيف متنوع من التطبيقات يمكنك الإطلاع عليها من خلال النقر على الرابط التالي لصفحة التوثيق الخاص بهذه المكتبة: https://justadudewhohacks.github.io/face-api.js/docs/ إن المثال الذي سوف نبنيه فيما يلي سيقوم باستخدام كاميرا حاسوبك أو جوالك من خلال صفحة ويب ستقوم ببرمجتها بنفسك لكي يأخذ صورة المستخدم ويقدّر منها عمره وجنسه. تخيل لو أننا نتحدث عن صفحة تسجيل مستخدم جديد في تطبيقك المستقبلي، سيكون من اللطيف والذكي في آن معا لو استطاع التطبيق تحديد القيم الافتراضية للعمر والجنس بناء على صورة المستخدم بحيث تكون قريبة إلى الواقع بطريقة تحسن من تجربة المستخدم. تم بناء نموذج التعرف على العمر والجنس باستخدام شبكة عصبية صنعية متعددة المهام توظف فيها طبقة استخلاص سمات الوجه لتقدير العمر وكذلك لتصنيف الجنس، يبلغ حجم حزمة النموذج بالإجمال قرابة 420kb، وقد تم تدريبها واختبارها باستخدام قواعد بيانات متعددة لصور الوجوه الموسومة بالعمر والجنس الحقيقيين (منها على سبيل المثال موسوعة Wikipedia وقاعدة IMDB للأفلام والممثلين)، وتبلغ دقتها 95% في تحديد الجنس، وهامش خطئها في تحديد العمر يقارب 4 سنوات ونصف. استخدام الشبكات العصبية في نافذة متصفحك لنقم بداية بإنشاء مجلد جديد وليكن اسمه face-api للمشروع الذي سنعمل عليه اليوم ضمن مخدم الويب المحلي الذي لديك لتجربة تطبيقات الويب التي تعمل عليها (أي ضمن المجلد C:\xampp\htdocs على سبيل المثال في حال كنت تستخدم مخدم XAMPP)، سنضيف داخل ذلك المجلد الرئيسي مجلدين فرعيين باسم js وكذلك models، ومن ثم نقوم بنسخ الملفات التي نحتاجها من مكتبة Face-API الأصلية على الشكل التالي: نُنزِّل الصيغة المصغرة/المضغوطة من المكتبة ذاتها (أي الملف "face-api.min.js") ونسخها إلى داخل المجلد الفرعي js في مشروعنا، يمكن الحصول على ذلك الملف من العنوان التالي: https://github.com/justadudewhohacks/face-api.js/tree/master/dist نُنَزِّل نماذج الشبكات العصبية الصنعية التي سنستخدمها، حيث يوجد ملفين لكل نموذج شبكة عصبية أحدهما ينتهي إسمه بكلمة "shard1" تحفظ فيه قيم أوزان الشبكة، أما الآخر فهو ملف بصيغة json يصف بنية الشبكة حتى يتم قراءة وتحميل قيم الأوزان السابقة بشكل سليم. في مثالنا الحالي سنحتاج إلى استخدام شبكتين عصبيتين هما "age_gender_model" و "tiny_face_detector_model"، أي أننا بحاجة إلى تنزيل أربع ملفات ومن ثم نسخها إلى داخل مجلد models في مشروعنا. يمكنك الحصول على تلك الملفات من العنوان التالي: https://github.com/justadudewhohacks/face-api.js/tree/master/weights بعد ذلك سنُنشِئ ملفين جديدين أحدهما سندعوه index.html سنضعه في المجلد الرئيسي للمشروع، أما الآخر فسندعوه main.js ونضعه ضمن المجلد الفرعي js المخصص لشيفرات لغة JavaScript البرمجية. سنقوم بداية بتنقيح محتوى صفحة HTML والتي سنجعلها بأبسط شكل ممكن بغرض التركيز على العناصر الأساسية التي نهتم بها: <html> <head> <title>Face-API Example</title> </head> <body> </body> </html> ضمن قسم body سنقوم بإضافة عنصر div فيه عنصر video لعرض الفيديو الذي تلتقطه كاميرا حاسوبك ندعوه webcam، ويتم ضبطها لتعمل تلقائيا ضمن النمط الصامت بمجرد تحميل الصفحة: <div class="container"> <video id="webcam" height="360" width="360" autoplay muted></video> </div> ثم نضيف حقل إدخال input مخصص للعمر ندعوه age: Age (years): <input id="age" size="3"><br /> بعد ذلك نضيف مجموعة أزرار اختيار من نوع radio ندعوها gender فيها اختيارين اثنين هما male وfemale: <input id="male" type="radio" name="gender" value="male">Male<br /> <input id="female" type="radio" name="gender" value="female">Female<br /> أخيرا وبعد اكتمال تحميل وعرض كافة عناصر الصفحة، نقوم بتضمين ملفات جافاسكريبت في نهاية محتويات الصفحة حتى نكون متأكدين من وصولها برمجيا لكافة العناصر ضمن تلك الصفحة: <script src="js/face-api.min.js"></script> <script src="js/main.js"></script> ملاحظة هامة: بسبب إعدادات الأمان فإن معظم متصفحات الويب تعرض رسالة للمستخدم تبيّن رغبة الصفحة في الوصول إلى الكاميرا وتطلب الإذن للسماح لها بذلك. هذا كل ما هو مطلوب فعليا ضمن صفحة HTML الخاصة بهذا المثال، أما الآن فعلينا الانتقال إلى لكتابة شيفرات لغة جافاسكريبت التي ستقوم بتحميل نموذج الشبكة العصبية الصنعية، وتمرير صور الكاميرا إليه، ومن ثم قراءة الخرج الناتج عن الشبكة العصبية الصنعية وعرضه ضمن عناصر الإدخال المقابلة في صفحة HTML السابقة. لذلك سنبدأ بكتابة محتوى الملف main.js من الشيفرات البرمجية مع شرح مختصر لكل قسم منها، فالسطر الأول يقوم بتعيين اسم الثابت video للإشارة إلى العنصر المدعوة webcam ضمن صفحة HTML السابقة: const video = document.getElementById("webcam"); بعد ذلك نقوم بتحميل نموذجي الشبكتين العصبيتين الخاصتين بالتعرف على الوجوه ضمن الصورة وتحديد الجنس وتقدير العمر من خلال سمات تلك الوجوه وذلك باستخدام آلية الوعود Promise.all، ومن بعد إتمام ذلك يتم استدعاء التابع startVideo الذي سنقوم بتعريفه لاحقا: Promise.all([ faceapi.nets.tinyFaceDetector.loadFromUri("models"), faceapi.nets.ageGenderNet.loadFromUri("models") ]).then(startVideo); يقوم هذا التابع بقراءة دفق إشارة الفيديو من الكاميرا وعرضها ضمن الكائن video، فإن حدث خطأ يتم كتابة رسالة الخطأ ضمن console.error في المستعرض: function startVideo() { navigator.getUserMedia( { video: {} }, stream => (video.srcObject = stream), err => console.error(err) ); } ومن ثم نضيف حدث يقوم بالإنصات لما يتم عرضه ضمن عنصر video بحيث يستدعي بشكل غير متزامن async (أي دون الحاجة لانتظار الإجابة حتى يتابع عرض الفيديو) وذلك كل ثانية (حيث تم ضبط الفترة الزمنية setInterval لتكون قيمتها 1000 ميلي ثانية). يقوم هذا الاستدعاء الدوري المتكرر بتعيين قيمة الكائن detection بواسطة مكتبة faceapi حيث تحدد جميع الوجوه الموجودة ضمن كائن video بالاستعانة بنموذج TinyFaceDetector مستخدمين الإعدادات الافتراضية، ومن ثم يمرر الناتج (أي الوجوه التي تم التعرف عليها في الصورة)، إلى الشبكة العصبية الأخرى التي تتعرف على العمر والجنس: video.addEventListener("playing", () => { setInterval(async () => { const detections = await faceapi .detectAllFaces(video, new faceapi.TinyFaceDetectorOptions()) .withAgeAndGender(); إن العبارة الشرطية التالية تتأكد إن كان الكائن detections موجودا أصلا (تذكر أن تعيين قيمة هذا الكائن تتم من خلال استدعاء غير متزامن وبالتالي يمكن أن تكون القيمة غير موجودة في البداية ريثما تصل إجابة ذلك الاستدعاء). ليس هذا فحسب، بل يجب أن يتضمن على الأقل وجه واحد على الأقل. فإن تحقق هذين الشرطين يتم قراءة الجنس المتوقع للوجه الأول detections[0].gender وتعيينه لعنصر الإدخال المقابل له، وكذلك قراءة العمر المتوقع لذات الوجه الأول detections[0].age وتقريبه إلى أقرب عدد صحيح باستخدام التابع Math.round ومن ثم إسناده كقيمة لعنصر الإدخال المدعو age ضمن صفحة HTML السابقة: if (detections && Object.keys(detections).length > 0) { document.getElementById(detections[0].gender).checked = true; document.getElementById("age").value = Math.round(detections[0].age); } }, 1000); }); هذا كل شيء! تستطيع الآن تجربة هذا التطبيق البسيط من خلال عرض الصفحة على نافذة المستعرض مستخدمين عنوانها على مخدم الويب المحلي وليكن على سبيل المثال: http://localhost/face-api نقاط تستحق التأمل من منا لا تغريه كم الإسقاطات التي تطرحها تقنية الشبكات العصبية الصنعية على مفهوم البرمجة ككل؟ إنها بذور جيل جديد مختلف جذريا عن كل ما سبق وأن اعتدنا عليه، فرغم أنها تعتمد على وحدات بسيطة في صميمها هي العصبونات، والتي قمنا بوصف آلية عملها بطريقة خوارزمية محددة تماما وواضحة، إلا أننا مع نمو شبكاتنا في الحجم والتعقيد استبدلنا الثقة بالأمل، والتحليل بالتجريب. لنأخذ على سبيل المثال نموذج اللغة العربية، فحتى نستطيع تشكيل أي جملة نستخدم علم النحو والإعراب الذي تعلمناه في مدارسنا، ومن خلال قواعده نحدد بناء الجملة وعناصرها كالفعل والفاعل أو المبتدأ والخبر وسواها من القواعد التي تساعدنا على ضبط أواخر الكلمات. هذه هي تماما الطريقة التي نبرمج بها حواسيبنا حاليا (منذ أيام تشارلز بابيج وحاسوبه الميكانيكي قبل مئتي عام)، فنحن نضع القواعد الصارمة لتدفق البيانات ونترجمها إلى عبارات شرطية وحلقات وسواها من بنى التحكم في عدد منتهي من الخطوات ندعوها بالخوارزمية. لكن لحظة، هل هذه هي الطريقة الصحيحة فعلا التي تجري بها الأمور؟ هل هذا ما نفعله حقيقة عندما يلتبس علينا تشكيل كلمة ما في نص نقرأه أو جملة نتحدثها؟ أغلب الظن ستكون إجابتك هي النفي! فمعظمنا لا يعرب الجملة في رأسه ليضبط أواخر الكلمات، بل نجرب الاحتمالات المختلفة ونرى أيها يملك الوقع الأكثر تجانسا وانسجاما في نفسنا (على سبيل المثال: هل أباك/أبوك/أبيك موجود؟). إنها ببساطة ما ندعوه بالسليقة اللغوية، وهي التي تفسر قدرة الطفل الصغير على التكلم بلغة صحيحة حتى قبل معرفته بوجود علم النحو والإعراب أصلا، فهو يتعلم مما يسمع وينسج على منواله، فكلما كانت الأمثلة كثيرة وصحيحة ازداد اتقانه للغة (ولهذا السبب كان العرب يرسلون أبنائهم إلى البادية لسلامة اللغة من اللحن الأعجمي هناك). إن التعلم من خلال الأمثلة هو ما تقوم به تماما الشبكات العصبية الصنعية التي نقوم بتطويرها، إنها تقوم ببناء خبرتها وسليقتها وفراستها الخاصة، في نهاية المطاف يمتلك كل من المبتدئ والخبير القواعد ذاتها، لكن عين الخبير رأت الكثير من الأمثلة التي صقلت بها خبرتها، حتى وصلت من التعقيد إلى درجة قد يصعب معها التفسير رغم قوة الإحساس ووضوحه في ذهنه. وهكذا ينتقل دور المبرمج رويدا رويدا من وضع القواعد وبنى التحكم لبرمجياته إلى ما بات يدعى اليوم بعلم البيانات وهندسة عملية استخلاص المزايا والخصائص المؤثرة في عملية التعلم من تلك البيانات، حيث أن دقة وجودة النموذج الناتج تعتمد بشكل حاسم على تكامل أمثلة التعليم وشمولها وصحتها، وأصبح امتلاك مثل هكذا مكانز رقمية موصّفة بشكل دقيق ومبنية بطريقة هيكلية سهلة الولوج والاستعلام يعادل قطع ما يتجاوز نصف الطريق إلى الوصول لعالم الذكاء الصنعي التطبيقي وقطف ثماره. دورة الذكاء الاصطناعي احترف برمجة الذكاء الاصطناعي AI وتحليل البيانات وتعلم كافة المعلومات التي تحتاجها لبناء نماذج ذكاء اصطناعي متخصصة. اشترك الآن مراجع للاستزادة مكتبة TensorFlow مكتبة face-api.js Model optimization اقرأ أيضًا المقال السابق: تصنيف الصور والتعرف على الوجه في مجال الذكاء الاصطناعي المفاهيم الأساسية لتعلم الآلة
  2. الذكاء الصنعي وخوارزميات تعلم الآلة AI/ML تتفق جميع التقنيات والخوارزميات التي تندرج تحت مسمى الذكاء الصنعي Artificial Intelligence وتعلم الآلة Machine Learning باختلاف أطيافها على البدء بتحليل البيانات الخام والبحث فيها (بطرق خوارزمية ممنهجة) لاستكشاف ما تحتويه من أنماط وعلاقات في داخلها وبين كياناتها. إن معرفة مثل تلك الأنماط والعلاقات ستساعدنا على بناء نماذج قادرة على استقراء الجوهر العام المشترك الذي يجمع ويصنف تلك الكتل من البيانات على الرغم من الاختلافات في التفاصيل الهامشية والتي قد تكون كبيرة ظاهريا ومربكة في عين من لا يتمتع بالخبرة في مجال الدراسة. لقد أثبتت مثل هذه النظم فعاليتها في حوسبة العديد من المهام التي كان يعتقد حتى وقت قريب أنها عصية على عالم البرمجيات، ساعد على ذلك الطفرة التي شهدتها عتاديات الحواسيب في العقد الأخير والتقدم الهائل في إمكانيات الحوسبة المتوازية لوحدات المعالجة الرسومية GPU، وكذلك توافر حلول الحوسبة السحابية لشريحة أكبر من فرق التطوير البرمجية التي كان يصعب عليها في الماضي الحصول على حواسيب فائقة بسهولة. إننا نشهد في الفترة الحالية انتقالا وتحولا جذريا في مفاهيم علم البرمجة مقارنة بما سبق وبما تعلمناه أو استخدمناه خلال القرن الماضي (كالبرمجة الوظيفية ومخططات سير العمل، أو حتى البرمجة الغرضية التوجه بكائناتها وطرائقها)، فالمبرمج هو من كان يضع منطق العمل وخوارزميته ليحدد أسلوب معالجة المدخلات وتوليد المخرجات، وقد امتازت فترة ثمانينيات وتسعينيات القرن الماضي بوفرة القدرة الحاسوبية مقارنة بكمية البيانات المتوافرة للمعالجة أصلا، لكن ما نشهده الآن في القرن الحادي والعشرين قد قلب هذه المعادلة رأسا على عقب، فقد أصبح لدينا فائض كبير من البيانات التي تجمع من كل حدب وصوب على مدار الساعة بدءا من جوالاتنا (التي ما عادت وسيلة للاتصال فقط) وصولا إلى الأقمار الاصطناعية في مداراتها حول الأرض. إن هذا المستوى العالي من الأتمتة في حياتنا ومجتمعاتنا نتج عنه كم هائل من البيانات التي تجاوزت بمراحل القدرة على تحليلها واستخلاص المعلومات منها بالطرق التقليدية، وهو ما أعاد فتح الأبواب مجددا لتقنيات الذكاء الصنعي التي كان لها مجد سابق منتصف القرن الماضي لكنه زال بعد أن عجزت القدرات العتادية في ذلك الحين عن مواكبة شطحات المتنورين من رواد هذا الحقل من العلوم، لكننا اليوم وبتضافر جهود الباحثين في مجالات شتى مثل علم البيانات والإحصاء والحواسيب بلا شك، أصبحنا قادرين على تنفيذ ما كانوا يتحدثون عنه ضمن طيف واسع من التطبيقات ربما بات يتجاوز أقصى طموحاتهم. الشبكات العصبية Neural Networks في جزء من لوحة رافائييل الجصيّة "مدرسة أثينا" تم رسم أفلاطون وأرسطو بشكل يعبّر عن نظريّة كل منهما في المعرفة، فأرسطو يومئ نحو الأرض فيما يشير أفلاطون بإصبعه نحو السماء، حيث كان ينظر أرسطو إلى الطبيعة بحثا عن إجابات في حين أن أفلاطون يبحث عن المثالي. وها نحن ننتقل في عالم البرمجة من فلسفة أفلاطون التي كنا نتّبعها في أدوات بناء تطبيقاتنا من لغات برمجة وما تحويه من متغيرات وتوابع وعبارات شرطية وحلقات وسواها، إلى فلسفة أرسطو حيث نبحث في كيفية عمل أدمغتنا ونحاول محاكاتها في بنيتها وطريقة عملها، وهكذا تماما ولد مجال الشبكات العصبية ضمن علوم الذكاء الصنعي. حيث ابتدأت المحاكاة على مستوى الخلية العصبية (العصبون)، فالعصبونات هي خلايا تتألف من جسم مركزي يتضمن نواة الخلية ويمتد منه استطالة وحيدة تكوّن ليف عصبي طويل يقوم مقام السلك الناقل للإشارة الخارجة من الخلية عند نهايته تفرعات كثيرة تنتهي بعقد مشبكية صغيرة، أما في الطرف الآخر من جسم الخلية العصبية فتبرز تفرّعات تخرج في كافة الاتجاهات والتي عن طريقها ترد إلى جسم الخلية البيانات الداخلة، ولابد للإشارات لكي تمر من عصبون إلى آخر أن تجتاز الفجوة الضيقة ما بين عقدة المشبك والجسم أو التفرّع للعصبون التالي. تتلقى الخلية العصبية عدة تنبيهات من الخلايا المجاورة تؤدي إلى شحنها، فإذا وصلت تلك الشحنة إلى عتبة معينة ينبثق كمون كهربائي عند قاعدة المحور وينتشر دفعة واحدة على طوله. لا تستجيب العصبونات لمختلف التنبيهات بشكل متشابه، فلكل منبه درجة أهمية تزيد أو تنقص، كما أن خرج العصبون لا يمتاز بالتدرج، فإما أن تكون هناك نبضة عصبية تنتشر عبر المحور إلى الخلايا المجاورة أو لن يكون هنالك شيء على الإطلاق. طبعا هذا الوصف لبنية العصبون وطريقة عمله فيه تبسيط شديد لحقيقة الأمر، لكن هذا المستوى من الشرح يفي بالغرض. على الرغم من أننا عندما نحاكي عمل العصبون (بفرض أننا نعلم طريقة عمله تماما) لن نحصل على عصبون حقيقي، لكننا سنحصل على معالجة حقيقية للمعلومات كما لو كان العصبون هو من قام بها، وهذا هو بيت القصيد. إن التمثيل الرياضي للعصبون يفترض أن لدينا n إشارة دخل سنرمز إليها بالمقادير X1, X2, …, Xn يرتبط كل منها بوزن أو تثقيل للتعبير عن دور المشابك العصبية كون العصبونات لا تستجيب بشكل متشابه لمختلف التنبيهات كما اتفقنا سابقا. سنرمز إلى تلك الأوزان بالمقادير W1, W2, …, Wn والتي قد تكون قيما موجبة أو حتى سالبة تكبر أو تصغر بحسب طبيعة ودور إشارة الدخل المرتبطة بها سواء كانت محفّزة أم مثبّطة وإلى أي قدر هي كذلك. وهكذا يمكننا التعبير عن مجمل الدخل الآتي إلى العصبون المفرد بالشكل الرياضي التالي: من جهة أخرى، لتمثيل إشارة خرج العصبون نحتاج إلى دالة رياضية تستطيع توصيف عمل قانون الكل أو لا شيء تبعا لعتبة معيّنة، وهناك عدّة خيارات رياضية شائعة قد يتم تفضيل إحداها على الأخرى بحسب طبيعة البيانات التي نتعامل معها نذكر منها على سبيل المثال لا الحصر: Sigmoid (للقيم الثنائية 0/1 أو نعم/لا أو حتى ذكر/أنثى)، TanH (للفئات أو التصنيفات المتقطعة مثل الأعراق: عربي، أوروبي، أفريقي، آسيوي، هندي، الخ.)، وكذلك ReLU (للقيم المتصلة كالعمر مثلا). يوضح الشكل التالي الصيغة الرياضية والتمثيل البياني الذي يظهر العلاقة فيما بين الدخل والخرج لكل منها: بعد أن قمنا بتوصيف العصبون بشكل رياضي مبسّط، علينا الانتقال للحديث عن بنية الشبكات التي تنتظم بها تلك العصبونات وطرق ارتباطها بعضها ببعض، سنتناول بالشرح شكلا واحدا من أشكال بناء الشبكات العصبية، لكن ذلك لا يعني عدم وجود معماريات أخرى لبناء تلك الشبكات. سنفترض أن العصبونات تنتظم في طبقات ولكل طبقة عدد من العصبونات بحيث أن خرج أي عصبون من هذه الطبقة يتم إيصاله إلى كل عصبونات الطبقة التالية. يمكن تمييز الطبقة الأولى على أنـها طبقة الإدخال والتي تتلقى بياناتها من الوسط الخارجي للشبكة العصبية، كذلك نعرّف طبقة الإخراج على أنـها الطبقة الأخيرة والتي ترسل ناتج معالجة البيانات ثانية إلى الوسط الخارجي، في حين يسمّى كل ما عدى ذلك من طبقات بين هاتين الطبقتين بالطبقات الخفية. كما نلاحظ فإن عدد العصبونات في كل من طبقتي الإدخال والإخراج محدد بحسب طبيعة الوظيفة المناطة بالشبكة العصبية (مثلا عدد العنصورات Pixels الإجمالي في الصورة لكل قناة لونية RGB في الدخل، وعدد الفئات المراد تصنيفها في الخرج)، أمّا عدد الطبقات الخفية وعدد العصبونات في كل منها فلا توجد قواعد ضابطة وواضحة لذلك. مكتبة TensorFlow من Google مكتبة TensorFlow هي منصة متكاملة لتدريب وبناء تطبيقات الذكاء الصنعي وتعلم الآلة بالاعتماد على تقنية الشبكات العصبية طورتها شركة Google باستخدام لغة Python ونشرتها تحت ترخيص البرمجيات الحرة والمفتوحة المصدر، وهي تعد في الوقت الراهن واحدة من أكثر المكتبات شهرة واستخداما في هذا المجال (رغم أنها ليست الوحيدة قطعا)، وذلك نظرا لغزارة وتنوع المصادر والأدوات المتوافرة لها والتي تتيح للباحثين القدرة على بناء واستخدام تطبيقات الذكاء الصنعي في أعمالهم. للمزيد حول TensorFlow يمكنكم الإطلاع على الموقع الرسمي لها على الرابط التالي: https://www.tensorflow.org دورة الذكاء الاصطناعي احترف برمجة الذكاء الاصطناعي AI وتحليل البيانات وتعلم كافة المعلومات التي تحتاجها لبناء نماذج ذكاء اصطناعي متخصصة. اشترك الآن مكنز TensorFlow Hub للنماذج إحدى أهم التحديات في عالم الذكاء الصنعي بشكل خاص، وعلوم البيانات بشكل عام، هي القدرة على إعادة استخدام ما سبق وما توصل إليه فريق تطوير آخر سابقًا، لذا قدمت Google هذا المكنز لوضع طريقة معيارية في مشاركة نماذج الشبكات العصبية بحيث تتضمن كافة المعلومات المطلوبة لإعادة استخدامها سواء كانت بنية الشبكة العصبية ذاتها (من حيث عدد الطبقات، ونوعها، وعدد العصبونات في كل منها، ونوع الروابط فيما بينها، الخ.)، إضافة إلى قيم الوسطاء والأوزان المختلفة في تلك الشبكة العصبية بعد إتمام عملية تدريبها. يمكن أخذ هذه النماذج وإعادة استخدامها في مهام مختلفة أو حتى إعادة تدريبها بسهولة مستخدمين تقنية تدعى نقل التعلم والتي سنتحدث عنها لاحقا في هذا الدرس. لمزيد من المعلومات حول هذا المكنز يمكنكم زيارة الموقع الرسمي له على الرابط التالي: https://www.tensorflow.org/hub. نموذج MobileNet V2 للرؤية الحاسوبية تم تصميم هذه العائلة من نماذج الشبكات العصبية المخصصة لمهام الرؤية الحاسوبية عامة الأغراض مثل التصنيف وتحديد الأجزاء والعناصر في الصورة وسواها من الوظائف مع مراعاة المصادر المحدودة التي قد تكون متوافرة على الأجهزة المحمولة. إن القدرة على تشغيل تطبيقات التعلم العميق على أجهزة الجوال الشخصية ستحسن من تجربة المستخدم نظرا لأنها ستكون متاحة في أي زمان ومكان بغض النظر عن الحاجة إلى الاتصال بمصادر خارجية على الإنترنت، وهو ما سيترافق مع فوائد إضافية لجهة الأمان والخصوصية والاقتصاد في استهلاك الطاقة. لمزيد من المعلومات يمكنك الإطلاع على الرابط المدرج ضمن قسم المراجع1. تقنية نقل التعلم Transfer Learning إن النماذج الحديثة للتعرف على الصور تحتوي على الملايين من الوسطاء (من أوزان للروابط ما بين الآلاف من العصبونات المرصوفة في العشرات من الطبقات الخفية) والتي يتطلب تدريبها من الصفر كما كبيرا من بيانات التدريب من جهة، والكثير من الطاقة الحاسوبية من جهة أخرى (تقدّر بالمئات من ساعات الحساب على وحدات المعالجة الرسومية GPU أو حتى أكثر بكثير). إن تقنية نقل التعلم تعتمد على حيلة ذكية لاختصار كم المصادر الكبير الذي نحتاجه لتطوير نموذج رؤية حاسوبية جديد تخصص مهاراته في التعرف على نمط مختلف من الصور (مثلا صور الأشعة السينية لتشخيص وجود أورام سرطانية محتملة عوض التعرف على الأنواع المختلفة من الأزهار البرية). تقوم الفكرة على استبدال الطبقة الأخيرة فقط من شبكة عصبية سبق وأن تم تدريبها بشكل جيد على تصنيف الصور ولو لغايات مختلفة، مستفيدين بذلك من كم المهارات التي اكتسبتها بنية الطبقات الخفية في ذلك النموذج، ابتداء من التعرف على أنماط النسج والأشكال وترابط الأجزاء وعلاقات الألوان وغيرها مما هو مشترك بالعموم بين كافة نظم الرؤية الحاسوبية، والتي يمكن إعادة استخدامها ومشاركتها بين النماذج المختلفة. وحدها الطبقة الأخيرة فقط الخاصة بالأصناف تتغير بتغير الغاية والهدف من النموذج الذي يجري تطويره وتخصيصه، لذا هي وحدها التي سيتم تدريبها فعليا عند استخدام تقنية نقل التعلم هذه. لمزيد من المعلومات حول هذه التقنية في التعليم يمكنكم الإطلاع على رابط ورقة البحث العلمي المدرجة ضمن قسم المراجع أدناه2. تجهيز بيئة العمل سنستخدم منصة Docker المخصصة لتطوير ونشر وإدارة التطبيقات باستخدام فكرة الحاويات وذلك لتسهيل بناء بيئة العمل لدينا من أجل تنفيذ التطبيق العملي في هذه الجلسة، حيث أن الحاويات هي عبارة عن حزم تنفيذية خفيفة وقائمة بذاتها لتطبيق ما، تحوي كل المكتبات وملفات الإمداد والاعتماديات والأجزاء الأخرى الضرورية ليعمل التطبيق ضمن بيئة معزولة، هذا عدى عن أنها خفيفة لأنها لا تتطلب حملا إضافيا كالأجهزة الافتراضية كونها تعمل ضمن نواة النظام المضيف مباشرة دون الحاجة إلى نظام ضيف، وبذلك نزيل عن كاهلنا في هذه المرحلة أي تعقيدات تختص بالتنصيب والربط والإعداد لمختلف مكونات بيئة التطوير الخاصة بمكتبة TensorFlow وهي مهمة ليست باليسيرة على المبتدئ، لذا عليك القيام بتثبيت Docker على حاسوبك الشخصي من الموقع الرسمي https://www.docker.com/ قبل الانتقال إلى الخطوة التالية. اطلع على مقال «التعامل مع حاويات Docker» في قسم دوكر في أكاديمية حسوب. تطبيق عملي يقوم بتحديد جنس الشخص من صورة وجهه بداية نقوم بتنصيب TensorFlow على Docker ضمن حاوية تحت تسمية hsoub-ft، قد تتطلب هذه الخطوة بعض الوقت نظرا لكون حجم صورة الحاوية التي سيتم سحبها وتنزيلها عبر الإنترنت يتجاوز 1GB: docker pull tensorflow/tensorflow docker run --name hsoub-tf -it -d tensorflow/tensorflow:latest بعد ذلك نقوم بالدخول إلى سطر الأوامر ضمن الحاوية ونقوم بتنصيب الإصدار 2.0 على الأقل من مكتبة TensorFlow وكذلك الإصدار 0.6 على الأقل من نموذج تصنيف الصور3 الذي سنستخدمه والمستضاف في مكنز TensorFlow Hub، و بعد إتمام هذه الخطوات نخرج باستخدام الأمر exit في سطر الأوامر للعودة إلى الجهاز المضيف: docker exec -it hsoub-tf bash pip install "tensorflow~=2.0" pip install "tensorflow-hub[make_image_classifier]~=0.6" exit الخطوة التالية هي تحضير بيانات التدريب وذلك من خلال الحصول على الصور التي سيتم تدريب الشبكة عليها، في مثالنا هذا استخدمنا مجموعة جزئية تتكون من حوالي 2000 صورة مقسمة إلى فئتين ذكور وإناث وهي مقتطعة من مجموعة بيانات أكبر تدعى UTKFace4 المتاحة للاستخدامات غير التجارية والتي تتضمن بالأساس ما يزيد عن 20 ألف صورة وجه. تم اختيار الصور التي سوف نستخدمها في عملية التدريب بحيث تكون متوازنة من حيث الجنس (أي أن عدد الصور الخاصة بالذكور يساوي تقريبا عددها للإناث) والعرقيات (أي تقارب عدد الأشخاص من ذوي الأصول الأوروبية والأفريقية والهندية الخ.) وذلك لضمان عدم التحيز، إضافة إلى أن الصور تخص أشخاصا تتراوح أعمارهم ما بين 20 إلى 40 سنة. للمتابعة عليك تحميل الملف المضغوط المرفق مع هذا المحتوى، ثم قم بفك ضغطه على حاسوبك وستحصل على مجلد باسم training داخله ثلاث مجلدات هي images و output وكذلك test. ستلاحظ ضمن مجلد images أن هنالك مجلد فرعي لك تصنيف تريد من شبكتك العصبية أن تتعرف عليه (في حالتنا هذه هناك مجلدان فقط بتسمية Male و Female) داخل كل منهما مجموعة الصور التي تنتمي إلى ذلك التصنيف. من جهة أخرى فإن مجلد output هو فارغ حاليا لكنه المكان الذي سيتم فيه حفظ الشبكة العصبية بعد إتمام عملية تدريبها (أي حيث سنخزن النموذج الناتج)، أخيرا ستجد في المجلد الثالث test شيفرة برمجية بسيطة لاختبار النموذج الناتج وبعض الصور التي لم يسبق له أن رآها من قبل (أي أنها لم تكن موجودة أصلا ضمن صور وبيانات التدريب). نحن بحاجة إلى نقل كل هذه المجلدات وما فيها من ملفات إلى داخل الحاوية hsoub-tf وذلك باستخدام الأمر التالي على الجهاز المضيف: docker cp .\training hsoub-tf:/training الآن نستطيع الانتقال مجددا إلى سطر الأوامر ضمن الحاوية باستخدام الأمر التالي: docker exec -it hsoub-tf bash وبعد ذلك يمكننا بدء عملية التدريب باستخدام الأمر التالي: make_image_classifier \ --image_dir training/images dir \ --tfhub_module https://tfhub.dev/google/tf2-preview/mobilenet_v2/feature_vector/4 \ --image_size 224 \ --saved_model_dir training/output/model \ --labels_output_file training/output/class_labels.txt \ --tflite_output_file training/output/mobile_model.tflite إن وسطاء الأمر التنفيذي السابق تحدد المسار الذي يحتوي على مجلدات الصور التي سيتم استخدامها في عملية التدريب (أي مسار المجلد ضمن الحاوية وليس على الجهاز المضيف)، وكذلك مصدر النموذج الأصلي الذي ستطبق عليه تقنية نقل التعلم باستبدال طبقته الأخيرة، بعد ذلك نحدد الأبعاد المطلوبة للصور ليتم تحجيمها تلقائيا لتلائم هذه الأبعاد (فهذا محدد ومرتبط بطبقة الإدخال في نموذج الشبكة العصبية المستخدمة)، في حالتنا نحن نستخدم نموذج MobileNet V2 والذي يفترض أبعاد الصورة هي 224 عنصورة/بيكسل للطول والعرض، بعد ذلك نحدد المكان الذي سيتم فيه حفظ النموذج المدرّب الناتج، وكذلك أين سيتم حفظ التسميات المرافقة لعصبونات الخرج من شبكتنا العصبية بالترتيب، وأخيرا أين سيتم تصدير هذا النموذج بصيغة tflite المحزومة والموضبة لتطبيقات الجوال. في نهاية عملية التدريب (والتي قد تطول تبعا لعدد الصور من جهة، ولسرعة الحاسوب الذي تتم عليه عملية التدريب من جهة أخرى)، سنجد أننا حصلنا على نموذج شبكة عصبية يستطيع تمييز جنس الشخص من صورته بدقة تتعدى 80% وذلك بمجهود بسيط جدا دون الحاجة إلى عمليات ضبط ومعايرة فائقة التخصص لوسطاء بناء وتدريب الشبكة العصبية، ودون الحاجة كذلك إلى ساعات وساعات من التدريب ولا إلى آلاف وآلاف من الصورة للتدرب عليها! إنها بحق نتيجة مرضية لأوائل مغامراتك مع الشبكات العصبية، لكنها مجرد البداية. ها قد حان الوقت لتجربة النموذج الذي قمنا بتدريبه على صور لم يسبق له أن رآها من قبل، للقيام بذلك سوف نستخدم برنامج معد مسبقا لهذه الغاية5 وهو مكتوب بلغة Python وموجود داخل المجلد training/test صحبة بضعة صور كأمثلة للتجريب (ويمكن أن تستخدم صورك الخاصة في هذه المرحلة)، حيث ستتم عملية الاختبار لكل صورة من خلال الأمر التالي (وفيه نشير إلى مسار الشبكة العصبية التي سيتم تحميلها واستخدامها، والملف النصي الذي يتضمن اسم التصنيف الخاص بكل عصبون خرج ضمن هذه الشبكة بالترتيب، وأخيرا مسار الصورة المراد تصنيفها): python training/test/label_image.py \ --input_mean 0 --input_std 255 \ --model_file training/output/mobile_model.tflite \ --label_file training/output/class_labels.txt \ --image training/test/Ahmed_Zewail.jpg بعد إتمام تدريبنا واختبارنا للشبكة العصبية حان الوقت للخروج من بيئة التدريب هذه باستخدام الأمر exit للعودة إلى سطر الأوامر على الجهاز المضيف، ومن ثم سنرغب طبعا باستخراج النموذج الذي قمنا بتعليمه خلال هذه الجلسة من داخل حاوية Docker وهو ما نستطيع القيام به باستخدام الأمر التالي: docker cp hsoub-tf:/training/output .\training نقاط تستحق التأمل قد يرى البعض في تقنيات الذكاء الصنعي حلا لجميع المشكلات، لكنها في حقيقة الأمر لا تأتي خالية من المخاطر التي قد ترقى إلى حد اعتبارها نقاط ضعف أو عيوب يجب أن تؤخذ بعين الاعتبار، نذكر منها: باعتبار أن النماذج في الشبكات العصبية تبنى انطلاقا من بيانات التدريب، لذا فإنها غير قادرة على حل أي مشاكل كانت موجودة أصلا في تلك البيانات كالأخطاء أو الانحياز أو عدم التكامل والشمول لمختلف الحالات المراد التعامل معها. يصعب في الشبكات العصبية تفسير المنطق الذي استخدمه النموذج لإعطاء إجابته، فالتعامل معه أقرب ما يكون للصندوق الأسود الذي لا نعلم كمستخدمين آلية عمله الدقيقة في الداخل، بل نؤمن بأن ما نحصل عليه من إجابات هو أفضل المتاح، ولهذه الفكرة تداعياتها الفلسفية والاجتماعية التي تصعّب من استخدام هكذا أدوات في الحالات التي تتطلب تقديم تبرير (مثلا عند تطبيق عقوبة أو حرمان من مكافأة). تطوير نماذج الشبكات العصبية يتطلب قدرا كبيرا من بيانات التدريب المشروحة والمجهزة بشكل جيد وملائم، وهو ما قد يعني الكثير من الجهد لتوفير مثل هكذا مصادر للتدريب. عملية تدريب الشبكات العصبية هي عملية متطلّبة من ناحية قدرات المعالجة الحسابية المتوفّرة للعتاد المستخدم، وذلك على عكس عملية استخدامها في التطبيقات عقب إتمام التدريب، لذا قد يجد المطور في الحوسبة السحابية فرصا متاحة بميزانيات في المتناول. إن بناء النماذج باستخدام خوارزميات تعلم الآلة يتطلب مطورين أذكياء وموهوبين، فعلى الرغم من أن تطبيق المثال الذي قمنا بعرضه يبدو سهلا ويسيرا، إلا أن نظرة أكثر تعمقا ستكشف لك الكثير من التفاصيل التي بحاجة إلى معايرة وضبط، منها على سبيل المثال لا الحصر: معمارية الشبكة، وطريقة توصيف تابع تفعيل العصبونات فيها، وعدد طبقاتها الخفية، وعدد العصبونات في كل منها، وطريقة ربطها بعضها ببعض، وكيفية حساب الخطأ ما بين النتيجة المحسوبة والمطلوبة، ومعدل سرعة التعلم، وعدد مرات تكرار عرض الأمثلة على الشبكة العصبية أثناء التدريب، وغيرها الكثير. إن انتقاء التوليفة الأكثر ملائمة لجملة معايير الضبط هذه يؤثر بشكل حاسم على جودة ودقة النموذج الناتج. مراجع أجنبية للاستزادة MobileNetV2: The Next Generation of On-Device Computer Vision Networks DeCAF: A Deep Convolutional Activation Feature for Generic Visual Recognition Making your own TensorFlow model for image classification UTKFace: Large Scale Face Dataset TensorFlow Lite Python image classification demo اقرأ أيضًا تعلم الذكاء الاصطناعي الذكاء الاصطناعي: دليلك الشامل المقال التالي: إعداد شبكة عصبية صنعية وتدريبها للتعرف على الوجوه الذكاء الاصطناعي: مراحل البدء والتطور والأسس التي نشأ عليها
  3. إن فك ترميز سلسلة نصية بصيغة JSON باستخدام الدالة json_decode أسرع كثيرا في التنفيذ من فك ترميز سلسلة نصية بصيغة XML باستخدام الدالة SimpleXML وذلك نظرا لأن صيغة JSON تصف فقط تسلسل من النصوص المتداخلة دون الحاجة إلى توفير واجهة DOM أو تحليل للسمات. لذا إن كان الأداء عنصرا حرجا في تصميمك (كالحاجة للتعامل مع كم كبير من البيانات) فقد يكون من المفيد الاعتماد على صيغة JSON لتبادل البيانات بدلا من XML إن كان بإمكانك الاختيار فيما بينهما.
  4. شكرا على هذه المقالة الجميلة والممتعة في قراءتها. أرغب في هذا السياق أن أشير إلى النسخ العربية من دوال date و mktime و strtotime والمتاحة ضمن مكتبة Ar-PHP التي تتيح للمطور التعامل التواريخ الهجرية والأسماء العربية للأيام والأشهر بأكثر من صيغة شائعة في المشرق أو المغرب العربي.
  5. إن أكثر المشاكل تحديا في التحليل الإحصائي هي تلك التي نتعامل معها في الحياة العملية بعيدا عن مقاعد الدراسة وتهذيب مسائلها النموذجية، ففي إطار العمل على أرض الواقع غالبا ما نجمع كمية كبيرة إن لم تكن هائلة من البيانات المتعلقة بالقضية المدروسة من كل حدب وصوب ومصدر دون أن نكون على يقين أو معرفة مسبقة أكيدة أيُّها يملك دورا في تفسير ما نراه من نتائج، فكيف بنا إن كنّا نرغب في تقدير مدى تأثير كل منها في توصيف السلوك العام للمنظومة وما يستتبع ذلك من ضرورة استكشاف طبيعة العلاقات والروابط الداخلية ما بين عناصر البيانات المختلفة التي لدينا. على سبيل المثال إن كان هناك 20 متغير مختلف تم جمعه أو قياسه، فسيكون لدينا بالنتيجة 190 علاقة ارتباط ثنائية محتملة يجب دراستها وأخذها بعين الاعتبار، حيث أن كل واحد من تلك المتغيرات العشرين يجب أن يحسب ارتباطه مع بقية المتغيرات التسع عشر الأخرى واحدا فواحد، ونظرا لأن علاقة الارتباط تعتبر علاقة تبديلية فلا فرق حينها ما بين حساب معامل الارتباط للمتغيرين س و ع أو حسابه بين المتغيرين ع و س، لذا سيكون العدد الكامل هو نصف ناتج جداء العددين 20 و 19 ويساوي 190 كما سبق وأن ذكرنا. من الواضح أن مثل هذا الأسلوب غير عملي أو فعّال كما توحي تطبيقاته النموذجية حينما يكون لدينا بضعة متغيرات فقط، ففي حالتنا هذه سننتهي إلى غابة من الأرقام وشبكة معقدة من العلاقات المحتملة والتي يصعب الإلمام بحجمها ومداها من خلال مجرد النظر والتمحيص في مصفوفة معاملات الارتباط التي سنحصل عليها. لمثل هكذا حالات وجد تحليل المكونات الرئيسية (Principle Components Analysis (PCA والذي يعد أحد التقنيات المستخدمة لتلخيص البيانات واختصارها، حيث يقوم بتحويل العدد الكبير من المتغيرات المترابطة ضمنا ولو بشكل جزئي إلى مجموعة أصغر بكثير من المتحولات المستقلة التخيلية، وهي تدعى عادة بالمكونات الرئيسية وتحسب أساسا من المتغيرات الأصلية بنسب ومقادير تزيد أو تنقص بحسب دور وتأثير كل منها، لتصف في نهاية المطاف أكبر قدر ممكن من المعلومات الموجودة في المجموعة الأصلية من البيانات التي لدينا. كما سبق وأن أشرنا في مقالات سابقة، تعد لغة R من اللغات التي صعد نجمها حديثا وبشكل سريع بمجال البرمجة العلمية في قطاعي الإحصاء والمعلوماتية الحيوية (bioinformatics)، حيث باتت معتمدة على نطاق واسع في كثير من الجامعات ومراكز البحث العلمية، وأصبحنا نرى استخدامها والإشارة إليها في المقالات المنشورة بالمجلات العلمية المحكّمة يزداد بشكل طردي ومتسارع، هذا عدى عن حقيقة كونها لغة حرة مفتوحة المصدر يخضع توزيعها لترخيص GPL الشهير. كل ذلك أدى إلى تزايد ما هو متوافر ومتاح على الشابكة (الإنترنت) من مصادر لها على توزع طيف تلك المصادر، فهناك الكتب الإلكترونية والدروس التعليمية وحتى المناهج الأكاديمية والدورات التدريبية إضافة إلى البرامج الجاهزة والمكتوبة بلغة R لتنفيذ هذه المهمة أو تلك، حتى أنها باتت تحظى ببعض الامتياز مقارنة بالعديد من العمالقة في قطاعي البرمجة الرياضياتية العلمية والإحصائية مثل SAS و SPSS وغيرهما، خصوصا من حيث توافر الأمثلة والتطبيقات للطرق والخوارزميات الحديثة، حيث يقاد هذا التوجه في معظمه عن طريق الجامعات ممثلة بطلاب الدراسات العليا يحفّزهم على ذلك سهولة بناء الإضافات في لغة R، ويعتبر هذا الأسلوب رغم ما قد يشوبه من نقاط ضعف تتعلق بموثوقية وجودة وغزارة تلك الإضافات الجديدة، والتي تتبع خبرة ومهارة مطوريها وناشريها، لكنها تبقى في القطاع العلمي والأكاديمي أفضل كثيرا من البدائل التجارية التي يعيبها إرتفاع ثمنها من جهة، ومن جهة أخرى بطئ إضافة التحديثات التي تعكس تطور القطاعات العلمية المختلفة، حيث أنها عادة ما تتبع دورة تجارية تتحكم بها الشركات المنتجة. تستطيع أن تقوم بتحميل لغة R من الموقع الرسمي لها على الرابط http://www.r-project.org، وعملية تنصيب هذه اللغة تخلو من التعقيدات، وبانتهاءها يمكنك تشغيل سطر الأوامر الخاص بها من خلال النقر على أيقونة اللغة على سطح المكتب، إن كل ما نكتبه تاليا سيكون داخل سطر الأوامر هذا. تأتي لغة R محزومة مع إطار بيانات افتراضي يدعى mtcars يتضمن بيانات مأخوذة من مجلة Motor Trend لعام 1974 تقارن فيها أحد عشر من مواصفات التصميم والأداء لأكثر من ثلاثين سيارة منتجة في العام 1973، وهي البيانات التي سنستخدمها في كل أمثلتنا ضمن هذه المقالة، للحصول على معلومات إضافية عن طبيعة محتوى هذه البيانات يمكنك كتابة الأمر التالي في سطر الأوامر: ?mtcars من جهة أخرى يمكنك اختصار طريقة الوصول إلى المعلومات ضمن إطار البيانات هذا عن طريق تنفيذ الأمر: attach(mtcars) والذي يجعلنا قادرين على استخدام تسميات مثل mpg بدلا من استخدام الطريقة المفصلة mtcars$mpg للدلالة على عدد الأميال المقطوعة بغالون البنزين الواحد على سبيل المثال. لنفترض بداية أن لدينا مجموعة من العناصر هي بحسب مثالنا طرازات مختلفة من السيارات حيث توصّف كل واحدة منها بالاعتماد على عدد من الصفات تشمل الوزن والحجم والتسارع وقدرة المحرك الحصانية وعدد الأميال المقطوعة بغالون البنزين الواحد وسواها من صفات (بالإجمال يحتوي إطار البيانات mtcars على 11 صفة مختلفة تخص 32 طراز من السيارات). ?mtcars attach(mtcars) head(mtcars) mpg cyl disp hp drat wt qsec vs am gear carb Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4 Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4 Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1 Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1 Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2 Valiant 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1 لو أننا أردنا دراسة تشابه هذه الطرز من السيارات بحسب واحدة من الصفات المقاسة ولتكن الوزن على سبيل المثال، لأمكننا إنجاز ذلك من خلال تمثيل بياني بسيط على مستقيم الأعداد حيث تتقارب فيه النقاط الممثلة للطرز المتشابهة فيما تتباعد النقاط الممثلة للطرز المختلفة وذلك دوما بحسب الصفة المدروسة (وهي في حالتنا هذه وزن السيارة كما سبق وأن أشرنا). حيث نرى أن طراز مثل تويوتا كورولا والهوندا سيفيك واللوتس متشابهة عند تحديد ذلك بحسب صفة الوزن فقط وفق مثالنا كونها جميعا الأقل وزنا ضمن المجموعة المدروسة، فيما طرز مثل كرايزلر وكاديلاك تتشابه مع بعضها البعض لكنها تقع في الطرف الآخر بحسب صفة الوزن ذاتها حيث أنها من بين الطرز الأكثر وزنا في ما هو موجود لدينا من بيانات. plot(wt*0, wt, xlab="", xaxt="n") text(wt*0, wt, row.names(mtcars), cex=0.5, pos=4, col="red") abline(v=0) يبقى هذا المنطق سائدا في تحديد ما هو مختلف أو متشابه بأسلوب بياني بسيط حتى وإن كنا نتحدث عن صفتين اثنتين معا في ذات الوقت، كأن نضيف قدرة المحرك الحصانية على سبيل المثال إلى الصورة، إذ عوضا عن إسقاط النقطة الممثلة لكل طراز من السيارات المدروسة على مستقيم الأعداد، نقوم بتمثيلها ضمن مستوي ثنائي الأبعاد سيناته تشير إلى قدرة المحرك الحصانية فيما عيناته تمثل وزن السيارة على سبيل المثال، وهنا يبقى مفهوم التجاور للمتشابهات والتباعد للمختلفات قائما وصحيحا كما هو موضح في الشكل التالي والذي نحصل عليه نتيجة تنفيذ التعليمتين الموضحتين أدناه. عند إلقاء نظرة أكثر تفصيلا بإضافة صفة القدرة الحصانية للمحرك نستطيع حينها التفريق بين طراز اللوتس ذي القدرة الحصانية التي تبلغ تقريبا ضعف ما يملكه طرازي تويوتا كورولا والهوندا سيفيك على الرغم من أنهم جميعا يمتلكون أوزانا متقاربة، تلك الطرز التي كنا نعتبرها متشابهة عند مقارنتها بحسب صفة الوزن فقط كما أسلفنا الذكر سابقا. plot(hp, wt) text(hp, wt, rownames(mtcars), cex=0.5, pos=4, col="red") بزيادة عدد الصفات المراد أخذها بعين الاعتبار تبدأ الصورة بالتعقيد، فمع ثلاث صفات نحن بحاجة إلى الرسم في فضاء ثلاثي الأبعاد، أو على أقل تقدير سنحتاج إلى تطبيق بعض الحيل الرياضياتية لعرض هذه البيانات في رسم مسطح كأن نعتمد المخطط البياني الثلاثي Ternary Plot، فيما الحديث عن أربع صفات فما فوق يضع التمثيل البياني خارج إطار ما هو متاح من أساليب لتوصيف البيانات بغرض دراسة التشابه أو الاختلاف فيما بين عناصرها (يمكن في مثل هذه الحالات تطبيق تقنيات أخرى مثل العنقدة الهرمية للوصول إلى تلك الغاية). تقوم الفكرة الأساسية في تحليل المكونات الرئيسية PCA على تلخيص أكبر قدر ممكن من التباينات في مجموع الصفات المقاسة والتي تسهم في التمايز ما بين العناصر المدروسة، وذلك من خلال ابتداع عدد من الصفات التخيلية التي تحسب من مجموع الصفات الحقيقية لكن بأوزان متفاوتة تعكس دور كل منها وأهميته في التفريق ما بين تلك العناصر. تعمل خطوات تنفيذ الخوارزمية على حصر أكبر قدر ممكن من التباينات ضمن توليفة الصفة التخيلية الأولى والتي عادة ما يطلق عليها تسمية المكون الرئيسي الأول PC1، كما يتم حساب نسبة مؤوية لهذه الصفة التخيلية التي ابتدعناها تشير إلى الحصّة الكليّة من التباينات التي تم إلتقاطها والتعبير عنها في هذه الصفة التخيلية بالذات، تتابع خوارزمية تحليل المكونات الرئيسية PCA إنجاز عملها بأسلوب يشبه القضم، فبعد أن قامت من خلال ابتداع المكون الرئيسي الأول PC1 التعبير عن أكبر قدر ممكن من التباينات الموجودة ما بين العناصر المدروسة، ولنقل على سبيل المثال أننا استطعنا التعبير عن 60% من خلاله، حينها يأتي الدور على ابتداع المكون الرئيسي الثاني PC2 والذي سيقوم بدوره بمحاولة التعبير عن أكبر قدر ممكن من التباينات المتبقية والتي لم يستطع PC1 التعبير عنها، لذا فإن النسبة التي تمثل ما سيستطيع PC2 التعبير عنه من تباينات هي دوما أقل مما تم التعبير عنه في PC1، وهكذا دواليك بالنسبة لكل من PC3 و PC4 وصولا إلى PCn حيث n هي العدد الكلي للصفات المدروسة، وحينها تصل النسبة الإجمالية (التراكمية) إلى 100%، مع ملاحظة أنه من الممكن أن نصل إلى تلك النسبة قبل ذلك في حال كانت هناك مجموعة جزئية من الصفات المدروسة مستقرأة أو مستخلصة من صفات أخرى داخلة في ذات التحليل (كأن يكون لدينا وزن السيارة بالطن في صفة وبالكيلوغرام في صفة أخرى)، أو حتى لو كانت لدينا مجموعة جزئية من الصفات المدروسة عالية الارتباط فيما بينها لسبب أو لآخر. بمعنى آخر فإن ما نقوم به في هذا الحالة ما هو إلا شكل من أشكال تلخيص كمية المعلومات المقدمة على شكل عدد كبير من الصفات بصورة عدد مقتضب من المكونات الرئيسية (عادة ما نهتم بأول اثنين أو ثلاثة منها)، والتي ما هي إلا عبارة عن صفات تخيلية محسوبة كما سبق وأن أوضحنا بدلالة الصفات الحقيقية لكن بأوزان متفاوتة وضعت وحددّت لكي تعبّر عن أكبر قدر ممكن من التباينات التي تظهر ما بين عناصر المجموعة المدروسة. بهذا المنطق نرى أن الصفات التي لا تساهم في التفريق ما بين العناصر المختلفة في مجموعة البيانات التي ندرسها (وهي في حالتنا هذه طرز السيارات المختلفة) يكون لها أوزان صغيرة تقترب من الصفر، على نقيض الصفات التي تلعب دورا حاسما في التفريق ما بين العناصر المدروسة حيث يكون لتلك الصفات أوزان ذات مقادير كبيرة تقترب في قيمتها المطلقة من الواحد الصحيح، حيث لا أهمية هنا للإشارة سواء كانت موجبة أم سالبة طالما أن ما نبحث عنه هو وجود التأثير بحد ذاته. لابد أن تكون قد لاحظت أن قيم الأوزان المستخدمة في تثقيل أي من الصفات الداخلة في حساب المكونات الرئيسية (أي الصفات التخيلية الجديدة المبتدعة والتي تظهر في قسم Rotation ضمن مخرجات التابع prcomp) تتراوح ما بين -1 و +1، لذا فإما أن تكون جميع الصفات المستخدمة في وصف العناصر من ذات الرتبة (كأن تكون العناصر المدروسة هي مجموعة من الطلاب والصفات المستخدمة في دراسة التشابه أو الاختلاف بينهم هي علاماتهم الامتحانية في مجموعة من المواد)، فإن لم يكن الحال كذلك وجب علينا إجراء تقييس للمقادير الخاصة بالصفات الداخلة في التحليل قبل استخدامها في تحليل المكونات الرئيسية نفسه، وإلا ظهرت لدينا الصفة الأكبر قيمة من حيث المقادير المقاسة على أنها الصفة المسيطرة والمؤثرة على التمايز ما بين العناصر وذلك خلافا للصواب (فعلى سبيل المثال إن اختلافا بمقدار 0.5 طن في الوزن ما بين سيارتين يعد هاما في التفريق بينهما بقدر يفوق ما قد يعنيه الاختلاف في قدرة المحرك بمقدار 5 أحصنة على الرغم من أن الرقم 5 هو أكبر بعشرة أضعاف كقيمة مقارنة بالرقم 0.5). للتقييس طرق وأساليب متعددة منها على سبيل المثال التحويل إلى نسبة مؤية، أو التقييس إلى مجال يتدرج حتى الواحد الصحيح والذي يقابل القيمة العظمى للنطاق الحقيقي للقراءات المعنية، وهو ما يتم من خلال قسمة كافة القيم على مقدار القيمة العظمى تلك، أو يمكننا طرح قيمة المتوسط الحسابي من كافة القراءات وقسمتها على الإنحراف المعياري، فيصبح بالنتيجة المتوسط الحسابي للقراءات الجديدة المحولة هو 0 وانحرافها المعياري هو 1. إن إسناد القيمة TRUE للوسيط scale في التابع prcomp والذي ينفذ تحليل المكونات الرئيسية يطلب إلى الخوارزمية أن تقوم بعملية التقييس على البيانات قبل إجراء التحليل ذاته. pc <- prcomp(mtcars, scale=TRUE) pc Standard deviations: [1] 2.5706809 1.6280258 0.7919579 0.5192277 0.4727061 0.4599958 [7] 0.3677798 0.3505730 0.2775728 0.2281128 0.1484736 Rotation: PC1 PC2 PC3 PC4 PC5 mpg -0.3625305 0.01612440 -0.22574419 -0.022540255 0.10284468 cyl 0.3739160 0.04374371 -0.17531118 -0.002591838 0.05848381 disp 0.3681852 -0.04932413 -0.06148414 0.256607885 0.39399530 hp 0.3300569 0.24878402 0.14001476 -0.067676157 0.54004744 drat -0.2941514 0.27469408 0.16118879 0.854828743 0.07732727 wt 0.3461033 -0.14303825 0.34181851 0.245899314 -0.07502912 qsec -0.2004563 -0.46337482 0.40316904 0.068076532 -0.16466591 vs -0.3065113 -0.23164699 0.42881517 -0.214848616 0.59953955 am -0.2349429 0.42941765 -0.20576657 -0.030462908 0.08978128 gear -0.2069162 0.46234863 0.28977993 -0.264690521 0.04832960 carb 0.2140177 0.41357106 0.52854459 -0.126789179 -0.36131875 من جهة أخرى نحصل نتيجة تمرير خرج التابع prcomp سابق الذكر إلى تابع عرض وتلخيص النتائج في لغة R أي التابع summary على النسبة المؤية للتباينات التي تم التعبير عنها في كل من المكونات الرئيسية المحسوبة بشكل مستقل أو تراكمي مضافا إلى ما سبقها من مكونات رئيسية، وهو ما يمكن عرضه أيضا بشكل رسومي من خلال تمرير ذات الخرج السابق على تابع الرسم الافتراضي في لغة R وهو التابع plot والذي يظهر تلك النسب المؤية لكل واحد من المكونات الرئيسية ممثلة بالأعمدة ضمن مخطط بياني كما هو موضح أدناه. summary(pc) Importance of components: PC1 PC2 PC3 PC4 PC5 PC6 Standard deviation 2.5707 1.6280 0.79196 0.51923 0.47271 0.46000 Proportion of Variance 0.6008 0.2409 0.05702 0.02451 0.02031 0.01924 Cumulative Proportion 0.6008 0.8417 0.89873 0.92324 0.94356 0.96279 PC7 PC8 PC9 PC10 PC11 Standard deviation 0.3678 0.35057 0.2776 0.22811 0.1485 Proportion of Variance 0.0123 0.01117 0.0070 0.00473 0.0020 Cumulative Proportion 0.9751 0.98626 0.9933 0.99800 1.0000 plot(pc) بالعودة إلى التطبيق العملي لهذه التقنية، عادة ما نهتم بأول مكونين رئيسيين فحسب أي PC1 و PC2 والذين يعبران عن أكبر قدر ممكن من التباينات بين العناصر بحسب مجمل الصفات المدروسة والتي يمكن التعبير عنها بمتحولين إثنين فقط، وفي مثالنا يبلغ مجموع هاتين النسبتين 84%، فنحن الآن قادرون على أن نعود إلى استخدام الرسم البياني البسيط على مستوي ثنائي الأبعاد من خلال التعبير عن PC1 على محور السينات و PC2 على محور العينات في مخطط بياني نعلم أنه يعبر عن 84% من التباينات الكلية بحسب كافة الصفات المدروسة (عادة ما تكون أي نسبة تفوق 60% مرضية للكثير من الباحثين)، وهكذا فإن أي نقطتين متجاورتين تمثلان طرازين متشابهين من السيارات. وبالتالي بعد تنفيذ تحليل المكونات الرئيسية PCA باستخدام التابع prcomp يمكننا حفظ النتائج التي نحصل عليها ضمن متحول ما ثم نعيد تمريرها للتابع biplot والذي سيقوم بوظيفة إخراجها بشكل رسومي في مخطط بياني ثنائي الأبعاد سيناته تمثل المكوّن الرئيسي الأول PC1 وعيناته تمثل المكوّن الرئيسي الثاني PC2، حيث يتم إسقاط كل عنصر من البيانات المدروسة وتمثيله على شكل نقطة وحيدة في هذا الفضاء التخيلي ثنائي الأبعاد بعد حساب قيمة كل من مسقطيه PC1 و PC2 من خلال تعويض قيم صفاته الحقيقية في معادلة حساب كل منهما. إن كانت نسب تمثيل كل من PC1 و PC2 متقاربة أمكن لنا تبسيط التعامل مع محاور الإحداثيات على أنها متناظرة، وإلا وجب التنبّه إلى أنّ الفروقات على محور السينات هي أكثر معنوية أو أهمية من فروقات بنفس القدر على المخطط البياني لكن على محور العينات. biplot(pc, cex=0.75) بالإضافة إلى ذلك سيظهر لنا هذا المخطط البياني أسهما باللون الأحمر تمثل كل صفة من الصفات الداخلة في تحليل المكونات الرئيسية وهو ما يقدّم لنا المزيد من المعلومات المضافة التي تخص العلاقة ما بين الصفات ذاتها حيث أن تجيب الزاوية (أي قيمة التابع المثلثي cos) ما بين سهمين أي صفتين يمثل قيمة معامل الارتباط بينهما، حيث أن الصفات التي تفصل بين أسهمها زوايا حادة هي صفات بينها ارتباط إيجابي/طردي (أي كلما زادت قيمة الصفة الأولى زادت الثانية والعكس بالعكس، دون أن يدل ذلك بالضرورة على أي علاقة سببية بينهما بل مجرد ارتباط ظاهري)، كما هو الحال بالنسبة لصفتي القدرة الحصانية hp وعدد إسطوانات المحرك cyl، وتزداد قيمة معامل الارتباط بصغر الزاوية حتى إذا انطبق سهما الصفتين على بعضهما البعض كان الارتباط طرديا تاما حيث cos(0) = +1. بشكل مناظر يمكننا استنتاج الصفات المرتبطة مع بعضها البعض لكن بشكل سلبي/عكسي (أي كلما ازدادت قيمة الصفة الأولى نقصت الثانية والعكس بالعكس)، حيث أن الزاوية التي تفصل ما بين السهمين الممثلين للصفتين المقارن بينهما يجب أن تكون زاوية منفرجة، كما هو الحال بالنسبة لصفتي القدرة الحصانية hp وعدد الأميال المقطوعة بغالون البنزين الواحد mpg، وتزداد قيمة معامل الارتباط بازدياد قياس الزاوية وصولا إلى الزاوية المستقيمة والتي يبلغ قياسها 180 درجة (أي أن السهمين يقعان على استقامة واحدة لكن باتجاهين متعاكسين)، وحينها يكون الارتباط هو ارتباط عكسي تام حيث cos(180) = -1. في حين أنّ الصفات التي لها أسهم متعامدة أو قريبة من التعامد (أي أن الزاوية بينهما قريبة من 90 درجة) فهي تشير إلى صفات غير مرتبطة ببعضها البعض أي أنها صفات مستقلة، كما هو الحال بالنسبة لصفتي القدرة الحصانية hp وعدد الغيارات في علبة السرعة gear، حيث أن cos(90) = 0. كذلك لابد أنك قد لاحظت أن جميع الأسهم في هذا المخطط البياني تظهر متساوية الطول، يعود السبب في ذلك إلى أننا قمنا بإجراء عملية تقييس على البيانات المدخلة قبل تنفيذ تحليل المكونات الرئيسية PCA، وإلا كانت أطوال هذه الأسهم مختلفة وتعبر عن قيمة مساهمة كل واحدة من هذه الصفات في المقدار الكلي للتباينات المقاس ما بين عناصر البيانات المدروسة (في حالة مثالنا إن أهملنا الوسيط scale=TRUE عند استدعاء التابع prcomp لأصبح سهمي الإزاحة/الحجم disp والقدرة الحصانية hp هما وحدهما الطاغيين على المخطط كون الفروقات التي يتسببان بها هي من رتبة العشرات ما بين طرز السيارات المختلفة وتتجاوز بكثير أي صفات أخرى من حيث القيمة المطلقة قبل التقييس، لكن هذا الاستنتاج مضلل ويجب التنبّه إلى ضرورة التقييس في مثل هكذا الحالات). فائدة أخرى يمكن الحصول عليها من وجود أسهم الصفات المضافة إلى المخطط البياني ثنائي الأبعاد والذي يمثل فيه كل عنصر من عناصر البيانات بنقطة (في حالتنا هذه كل طراز من طرز السيارات المدروسة)، إذ أن كل نقطة موجودة على امتداد أحد الأسهم أو في إتجاهه تعني أن الطراز المقابل لها له قيمة تفوق المتوسط بالنسبة للصفة المعنية المرتبطة بالسهم الذي نقارن معه (تزداد بابتعاد النقطة أكثر فأكثر عن مركز الإحداثيات باتجاه الأطراف)، وبشكل مناظر فإن النقاط الموجودة في الاتجاه المعاكس لسهم الصفة المدروسة وراء مركز الإحداثيات تدل على أن هذا الطراز المعني بتلك النقطة له قيمة أقل من المتوسط العام لهذه الصفة مقارنة بكافة العناصر الموجودة في عينة البيانات المدروسة. بشكل عام نستطيع تمديد السهم ليمثل محورا وهميا خاصا بتلك الصفة بالذات، ومن ثم نستطيع الحصول على تقدير نسبي جيد لقيمة هذه الصفة لكافة العناصر الموجودة من خلال أخذ مساقط من كل نقطة بشكل عامودي على هذا المحور الفرعي/التخيلي. من التدقيق في المخطط البياني الناتج من تحليل المكونات الرئيسية PCA من خلال استدعاء التابع biplot نجد أن صفة mpg التي تمثل عدد الأميال المقطوعة بغالون البنزين الواحد ترتبط بشكل عكسي مع صفات مثل عدد إسطوانات المحرك cyl والحجم disp والوزن مقدرا بالطن wt وهذا يبدو منطقيا، ونرى من خلال ذات المخطط أن سيارة مثل هوندا سيفيك تعد إقتصادية إلى حد بعيد مقارنة بطراز مثل كومارو Z28 والذي يمكن وصفه على أنه واحد من أسوء الطرز المدروسة من جهة استهلاك الوقود، وهي تعد إقتصادية أيضا حتى مقارنة بطرز أخرى مثل فولفو 142E والذي على الرغم من كونه يقطع عدد من الأميال بغالون البنزين الواحد يفوق المتوسط العام لطرز السيارات المدروسة، إلا أنه لا يزال أقل كفاءة من الهوندا سيفيك كما هو موضح بالمخطط البياني. مراجع للاستزادة: http://en.wikipedia.org/wiki/Principal_component_analysis.
  6. يعد تحليل التباين ANOVA, Analysis of Variance واحدا من أكثر الأدوات شيوعا بالاستخدام في جعبة العاملين بالتحليل الإحصائي، لذا سنقوم في هذه المقالة بتغطية موضوع تنفيذ تحليل التباين باستخدام لغة R وتفسير النتائج التي سنحصل عليها نتيجة تطبيق مثل هكذا تقنية وذلك من وجهة نظر تطبيقية بحتة تبتعد عن التجريد الرياضي وتركز على النواحي العملانية. كما سبق وأن أشرنا في مقالات سابقة، تعد لغة R من اللغات التي صعد نجمها حديثا وبشكل سريع بمجال البرمجة العلمية في قطاعي الإحصاء والمعلوماتية الحيوية (bioinformatics) حيث باتت معتمدة على نطاق واسع في كثير من الجامعات ومراكز البحث العلمية، وأصبحنا نرى استخدامها والإشارة إليها في المقالات المنشورة بالمجلات العلمية المحكّمة يزداد بشكل طردي ومتسارع، هذا عدى عن حقيقة كونها لغة حرة مفتوحة المصدر يخضع توزيعها لترخيص GPL الشهير. كل ذلك أدى إلى تزايد ما هو متوافر ومتاح على الشابكة (الإنترنت) من مصادر لها على توزع طيف تلك المصادر، فهناك الكتب الإلكترونية والدروس التعليمية وحتى المناهج الأكاديمية والدورات التدريبية إضافة إلى البرامج الجاهزة والمكتوبة بلغة R لتنفيذ هذه المهمة أو تلك، حتى أنها باتت تحظى ببعض الامتياز مقارنة بالعديد من العمالقة في قطاعي البرمجة الرياضياتية العلمية والإحصائية مثل SAS و SPSS وغيرهما، خصوصا من حيث توافر الأمثلة والتطبيقات للطرق والخوارزميات الحديثة، حيث يقاد هذا التوجه في معظمه من طرف الجامعات ممثلة بطلاب الدراسات العليا يحفّزهم على ذلك سهولة بناء الإضافات لهذه اللغة، ويعتبر هذا الأسلوب رغم ما قد يشوبه من نقاط ضعف تتعلق بموثوقية وجودة وغزارة تلك الإضافات الجديدة، والتي تتبع خبرة ومهارة مطوريها وناشريها، لكنها تبقى في القطاع العلمي والأكاديمي أفضل كثيرا من البدائل التجارية التي يعيبها إرتفاع ثمنها من جهة، ومن جهة أخرى بطئ إضافة التحديثات التي تعكس تطور القطاعات العلمية المختلفة، حيث أنها عادة ما تتبع دورة تجارية تتحكم بها الشركات المنتجة. تستطيع أن تقوم بتحميل لغة R من الموقع الرسمي لها على الرابط http://www.r-project.org، وعملية تنصيب هذه اللغة تخلو من التعقيدات، وبانتهاءها يمكنك تشغيل سطر الأوامر الخاص بها من خلال النقر على أيقونة اللغة على سطح المكتب، إن كل ما نكتبه تاليا سيكون داخل سطر الأوامر هذا، علما أننا نستخدم في كل أمثلتنا إطار البيانات المدعو mtcars والذي يأتي محزوما مع اللغة بشكل إفتراضي، وللحصول على معلومات إضافية عن طبيعة محتوى هذه البيانات يمكنك كتابة الأمر التالي في سطر الأوامرmtcars? ولاختصار طريقة الوصول إلى المعلومات ضمن إطار البيانات ننفذ الأمر (attach(mtcars فنصبح قادرين على استخدام التسمية qsec على سبيل المثال بدلا من استخدام الطريقة المفصلة mtcars$qsec للدلالة على عدد الأميال المقطوعة بغالون البنزين الواحد. تعتبر تقنية تحليل التباين تعميما لما سبق وأن تعاملنا معه في اختبار t والذي ينحصر في تحديد معنوية الفروقات فيما بين مجموعتين اثنتين فقط من البيانات، في حين يستطيع تحليل التباين التعامل مع بيانات مقسمة إلى أكثر من مجموعتين بناء على معامل factor أو أكثر، حيث تلعب المعاملات هنا دورا جوهريا في توصيف طريقة تقسيم مجموعة البيانات التي لدينا، وفي المثال الذي سنتناوله في هذه المقالة سنستخدم cyl والذي يشير إلى عدد إسطوانات المحرك كصفة تستخدم للتمييز بين المجموعات، لذا علينا بداية أن نخبر لغة R بضرورة تحويل طبيعة بيانات الشعاع cyl لتصبح معاملة وذلك باستخدام الأمر التالي: cyl <- factor(cyl) حيث تجري عملية التحويل ويتم إسناد الشعاع الناتج مجددا إلى ذات التسمية، وحتى نرى طبيعة التغيير التي جرت على cyl يمكننا استخدام التابع summary بالشكل التالي: > summary(cyl) 4 6 8 11 7 14 والناتج يشير بوضوح إلى وجود ثلاث مجموعات من البيانات بحسب عدد إسطوانات المحرك، فلدينا 11 سيارة بمحركات ذات أربع إسطوانات، و 7 سيارات أخرى بمحركات ذات ستة إسطوانات، إضافة إلى 14 سيارة بمحركات ذات ثمانية إسطوانات. إن ناتج تنفيذ التابع summary يختلف باختلاف طبيعة شعاع القيم المرسل له، وللمقارنة سنطبق ذات التابع summary على الصفة qsec والتي تمثل المدة اللازمة لقطع مسافة ربع ميل مقدرة بالثواني إنطلاقا من حالة السكون، وهي الصفة التي سندرسها بعد قليل باستخدام تحليل التباين لنرى إن كانت هناك أية فروقات معنوية من حيث الزمن اللازم لقطع مسافة الربع ميل وذلك ما بين فئات المحركات الثلاث والمصنفة بحسب عدد إسطوانات المحرك (أي المحركات بأربع أو ستة أو ثمانية إسطوانات)، إن ناتج تطبيق التابع summary على صفة qsec سيظهر على الشكل التالي: > summary(qsec) Min. 1st Qu. Median Mean 3rd Qu. Max. 14.50 16.89 17.71 17.85 18.90 22.90 كما ترى فإن التابع عاملها على أنها قيمة مستمرة (وليست متقطعة ذات مستويات محددة كما هي الحال مع المعاملات)، وبالتالي قام التابع summary بعرض القيمة الصغرى والعظمى والوسيط إضافة إلى الربيعين الأول والثالث كتلخيص لهذه الصفة. ملاحظة: إن قمت بتحويل إحدى الصفات إلى معاملة عن طريق الخطأ باستخدام التابع factor الذي سبق ذكره، فبإمكانك عكس تلك العملية باستخدام الأمر التالي: x <- as.numeric(x) هناك العديد من التوابع المفيدة والتي يمكن تطبيقها على المعاملات نذكر منها التابع levels والذي يعيد شعاعا يحوي القيم الفريدة (غير المكررة)، وفي حالة المعاملة cyl سيكون الناتج على الشكل التالي: > levels(cyl) [1] "4" "6" "8" كذلك لدينا التابع nlevels والذي يعطي كناتج له عدد المستويات الفريدة للمعاملة المدروسة، وفي حالة cyl سنحصل على الخرج التالي: > nlevels(cyl) [1] 3 بمعنى وجود ثلاث مستويات أو أنواع مختلفة لعدد الإسطوانات في محركات السيارات ضمن العينة المدروسة. لنقم بداية برؤية طبيعة توزع الصفة qsec بحسب كل مستوى أو قيمة للمعاملة cyl وذلك من خلال المخطط البياني الصندوقي بتطبيق التابع التالي: boxplot(qsec~cyl, col="gray") واضح من الشكل المعروض أعلاه وجود فروق معنوية لمقدار الصفة qsec بين مستويات cyl المختلفة، لكننا بحاجة إلى إثبات ذلك بدليل عددي، وهو ما سنحصل عليه من تطبيقنا لتحليل التباين، وللقيام بذلك باستخدام لغة R عليك تنفيذ الأمر التالي (وحفظ ناتج التحليل ضمن اللائحة التي أسميناها هنا في هذا المثال model): model <- aov(qsec~cyl) ويعتبر جدول تحليل التباين العنصر الأول والأساسي بنواتج هذا التحليل والذي يمكن الحصول عليه من خلال تمرير اللائحة model إلى التابع summary والذي سيغير من جديد طريقة عرض ناتجه تبعا لنوع الوسيط المرسل له، وفي هذه الحالة سيكون الخرج على الشكل التالي: > summary(model) Df Sum Sq Mean Sq F value Pr(>F) cyl 2 34.606 17.3029 7.7938 0.001955 ** Residuals 29 64.382 2.2201 --- Signif. codes: 0 '***' 0.001 '***' 0.01 '*' 0.05 '.' 0.1 '' 1 سنقوم فيما يلي بشرح مكونات الجدول الناتج حيث أن وظيفة تحليل التباين الأساسية هي قياس كمية التباينات الكلية المقاسة في العينة المدروسة والتي تحسب من العلاقة: حيث نحسب الفرق ما بين كل قيمة من قيم العينة المدروسة وبين المتوسط العام لتلك العينة، والتربيع يستخدم للتخلص من الإشارة فالتباين موجود بغض النظر عن كونه أعلى أو أقل من المتوسط العام، كما يخدم التربيع في تعظيم أثر التباينات الكبيرة القيمة على حساب التباينات الصغيرة المقدار، بعد ذلك يقوم تحليل التباين بتوضيح مقدار التباينات التي تسببت فيها المعاملة المدروسة تحت البند Sum Sq (أي مجموع المربعات) المقابلة لسطر المعاملة (في حالتنا هي cyl والمقدار هو 34.606) فيما بقية التباينات المقاسة في العينة المدروسة والتي لم تستطع المعاملة cyl تفسيرها يتم اعتبارها قيم متبقية Residuals تعود إلى مؤثرات أخرى غير cyl موضوع التحليل (وفي حالة مثالنا هذا مقدارها 64.382). إن الإقرار بمعنوية معاملة ما يتطلب أن تكون التباينات التي تسببت بها أوضح تأثيرا (أي أكبر مقدارا) من تلك التي تتسبب بها المؤثرات المتبقية Residuals والتي تمثل تشويش التجربة، لكن المقارنة ما بين مجموع المربعات هنا هي مقارنة غير عادلة نظرا لكون المقدارين 34.606 و 64.382 يعودان لدرجتي حرية مختلفتين (يوضح مقدار درجة الحرية في العمود Df ضمن الجدول السابق، حيث أن عدد درجات الحرية للمعاملة cyl هو 2 ويحسب من العدد الكلي لقيم cyl الفريدة ناقص واحد، في حين أن العينة المدروسة تضم 32 سيارة فيكون بالتالي عدد درجات الحرية الإجمالي هو 31 أي 32 ناقص واحد، منهما درجتي حرية تم إسنادهما للمعاملة cyl فيتبقى 29 درجة حرية للـ Residuals). ملاحظة: قد تشير بعض المراجع أو البرمجيات الإحصائية للقيم المتبقية Residuals باستخدام تسمية خطأ التجربة Error كونها تباينات غير مرغوبة يختلف مسببها عن المعاملة المدروسة، لكننا نرى أنه من الأدق تسميتها بالقيم المتبقية كونها لا تعتبر أخطاء بقدر ما هي تباينات تعود لأسباب أخرى خارجة عن نطاق اهتمامنا، في جميع الأحوال كلما صغر هذا المقدار كلما تحسنت دقة نتائجنا. لتصبح عملية المقارنة عادلة ما بين التباينات المقاسة يجب توحيدها وحساب مقدار التباينات التي تتسبب بها كل درجة حرية واحدة لكل من المعاملة cyl والقيم المتبقية Residuals والتي تحسب ببساطة بتقسيم المقدار Sum Sq على عدد درجات الحرية Df لكل بند على حدة، وهو ما يتم عرضه ضمن العمود Mean Sq، هذه المقادير يمكن مقارنتها مباشرة. إحدى طرق المقارنة الأسهل هي حساب نسبة التباين VR, Variance Ratio والتي يشار إليها في الجدول السابق بالتسمية F Value أو ما اصطلح على تسميته بقيمة F المحسوبة. إن فكرة استخدام نسبة التباين VR تشبه إلى حد بعيد ما نقوم به حين توليف المذياع لاستقبال محطة إذاعية ما، فصوت التشويش في الخلفية لا مفر منه، وهو المقابل لمقدار التباينات المتبقية Residuals في حالة تحليل التباين ANOVA، أما صوت المذيع فيقابل في حالتنا هذه التباينات التي تتسبب بها المعاملة التي ندرسها، ونحن نعتبر الاستقبال واضحا حينما يكون صوت المذيع أعلى بقدر ملحوظ مقارنة بالتشويش الأبيض في الخلفية، لذا كلما زادت نسبة التباين VR زادت فرص ملاحظة وإثبات وجود الفروقات المعنوية. في حالتنا هذه فإن التباينات التي تسببت بها معاملة عدد الإسطوانات cyl قد كانت أوضح بأكثر من سبعة أضعاف مقارنة بالتباينات العشوائية المتبقية المقاسة والظاهرة في العينة المدروسة، في نهاية المطاف هذا المقدار العددي لا يقدم إجابة حاسمة هل تعتبر هذه الفروقات معنوية أم لا، لذلك يوضح العمود الأخير والمسمى (Pr >F) ما هو احتمال عدم وجود فروقات معنوية ما بين مستويات المعاملة cyl المختلفة (أي أننا نعمل بطريقة نقض الفرض)، فإن كان هذا الاحتمال قليلا بقدر كاف أمكننا رفض هذه الفرضية (عدم وجود فروقات معنوية)، والإقرار بمعنوية الفروقات المقاسة للتباينات فيما بين مستويات المعاملة cyl المدروسة (يعبر عن قيمة الاحتمال برقم يتدرج ما بين 0 والذي يشير إلى الاحتمال المستحيل، و 1 للاحتمال الأكيد. عادة ما يعتبر الحد 0.05 فما دون كافيا للإقرار بوجود فروقات معنوية بمعنى قبول هامش خطأ لا يتجاوز 5%). بالنسبة للمثال الذي بين أيدينا، من الواضح أن الفروقات ما بين مستويات cyl المختلفة معنوية بدلالة أن المقدار Pr (>F) صغير وهو في حدود 0.002 أي 0.2% وهي نتيجة تدعم ما سبق وأن رأيناه في المخطط الصندوقي بداية هذه المقالة، لكن هذه المرة بشكل عددي مثبت ومتحرر من الأهواء والإنطباعات الشخصية الضبابية. من الهام ذكره أن تحليل التباين وصحة نتائجه قائم على أربع فرضيات يجب توافرها في البيانات المدروسة وإلا كانت النتائج غير ذات جدوى ولا يصح أن يعتمد عليها من الناحية الإحصائية، هذه الفرضيات الأربع هي التالية (ومجددا سنورد هذه النقاط بإسلوب عملي بعيد عن التعقيدات الرياضياتية قدر المستطاع): يجب أن تتبع الأخطاء أو القيم المتبقية التوزع الطبيعي، بمعنى أن الأخطاء أو الفروق الصغيرة عن النموذج المحتسب باستخدام تحليل التباين يجب أن تكون أعلى احتمالا مقارنة بالأخطاء أو الفروقات الواسعة الكبيرة. ثبات تباين الأخطاء، أي أن مقدار الخطأ يجب أن يكون مستقلا عن المقدار المقاس للصفة المدروسة (وهي في مثالنا qsec)، والخرق الأكثر شيوعا لهذا الشرط يظهر على شكل تباينات أخطاء صغيرة حينما يكون المقدار المقاس صغيرا والعكس بالعكس. استقلالية الخطأ ما بين العينات المدروسة، بمعنى ضرورة عدم وجود انتظام أو نمط معين لمؤثرات أخرى على الصفة المدروسة سوى المعاملة قيد الدراسة، أي أن توزع الأخطاء ما بين العينات يجب أن يكون عشوائيا. في حال وجود أكثر من معاملة مدروسة، يجب أن يكون ناتج التأثير تلك المعاملات تراكميا. تتيح لنا لغة R مجموعة من أربع مخططات بيانية تساعدنا على التحقق من معظم الفرضيات الموضحة أعلاه، لذلك سنقوم بداية بالطلب من لغة R أن تقوم بتجهيز نافذة إخراج الرسوم البيانية لتعرض أربع مخططات دفعة واحدة إثنان في كل سطر وذلك من خلال تنفيذ الأمر التالي: par(mfrow = c(2,2)) بعد ذلك نطلب عرض تلك المخططات باستخدام الأمر التالي (لاحظ أن model هو ذاته اسم اللائحة التي حفظناها كخرج للتابع aov في بداية المقالة): plot(model) يمكنك كذلك الحصول على قيم المتوسطات المختلفة والمتعلقة بهذا التحليل عن طريق تنفيذ الأمر التالي: > model.tables(model, "means") Tables of means Grand mean 17.84875 cyl 4 6 8 19.14 17.98 16.77 rep 11.00 7.00 14.00 حيث نلاحظ أن المتوسط العام لعينة السيارات المدروسة جميعا يبلغ تقريبا 17.8 ثانية لقطع مسافة الربع ميل الأولى من لحظة بدء التسارع (وهي الصفة التي يشير إليها شعاع القيم qsec)، بمعنى أن أي سيارة من السيارات الـ 32 المدروسة تقطع الربع ميل الأول خلال 17.8 ثانية تقريبا، بعد ذلك نجد جدول متوسطات أكثر تفصيلا يعرض قيمة لكل فئة من فئات السيارات المدروسة والمقسمة بحسب التحليل السابق على أساس عدد الإسطوانات في محركاتها والتي تعبر عنها معاملة cyl كما سبق وأن رأينا، وفي هذه الحالة نرى أن أكثرها بطئا هي الفئة الأولى (ذات المحركات بأربع إسطوانات) حيث تحتاج هذه الفئة بالمتوسط إلى 19.1 ثانية تقريبا (وتضم هذه الفئة 11 سيارة)، تليها فئة السيارات ذات المحركات بستة إسطوانات (وفيها 7 سيارات) حيث يقترب متوسط الزمن اللازم لقطع مسافة الربع ميل الأول لهذه الفئة من المتوسط العام نفسه وبمعدل 18 ثانية تقريبا، لتأتي بعدها فئة السيارات الأعلى تسارعا بمحركاتها ذات الإسطوانات الثمانية والتي لا تحتاج في المتوسط إلى أكثر من 16.8 ثانية لقطع الربع ميل الأول إنطلاقا من حالة السكون (وتضم هذه الفئة 14 سيارة من أصل العينة المدروسة). لا يستقيم عرض قيمة متوسط حسابي ما دون ذكر مقدار الخطأ المرتكب في حسابه والذي يشير إلى مقدار تشتت القراءات أو القيم التي حسب منها ذلك المتوسط حول قيمة المتوسط نفسه، ومن المقادير التي تستخدم عادة لهذه الغاية نذكر الخطأ المعياري SE, Standard Error والذي يمكن حسابه في حالة تحليل التباين بقسمة مقدار التبيانات الخاصة بالقيم المتبقية بسبب درجة حرية واحدة (أي المقدار من العمود Mean Sq والسطر Residuals في جدول تحليل التباين) على عدد عينات/تكرارات كل فئة من المعاملة المدروسة، ومن ثم حساب الجذر التربيعي للناتج. لو كانت بياناتنا متوازنة (بمعنى أن عدد السيارات في كل فئة من فئات المحركات مقسمة بالتساوي بحسب عدد إسطواناتها)، لاستطعنا الحصول على قيمة الخطأ المعياري SE للمتوسطات المحسوبة من خلال إضافة الوسيط se=TRUE إلى التابع model.tables سابق الذكر، لكن الحالة المدروسة في مثالنا ليست متوازنة، وبالتالي علينا حساب الخطأ المعياري يدويا (يمكنك حساب الحد الأدنى والأقصى أو حتى المتوسط) بالطريقة التالية: SE.min = sqrt (2.2201 / 14) SE.max = sqrt (2.2201 / 7)لاحظ أن المقدار 2.2201 مأخوذ من جدول تحليل التباين ANOVA الذي عرض سابقا، وأن الرقم 14 يمثل أعلى عدد تكرارات وهو يخص السيارات التي تنتمي لفئة المحركات ذات الإسطوانات الثمانية، أما الرقم 7 فباتت دلالته واضحة فهو يمثل أدنى عدد تكرارات ويعود لفئة المحركات ذات الستة إسطوانات (من الواضح أنه كلما زاد عدد العينات المدروسة إنخفضت قيمة الخطأ المعياري المرتكب في حساب متوسطاتها). نستطيع إنطلاقا من مقدار الخطأ المعياري SE أن نوجد قيمة SED, Standard Error of Differences والتي تحسب من خلال العلاقة البسيطة التالية: SED = sqrt(2) * SEوهي القيمة التي تستخدم عادة لتمثيل الخطأ في مخطط الأعمدة للمتوسطات كما هو موضح بالشكل التالي: كذلك نستطيع حساب مقدار أقل فرق معنوي LSD, Least Significant Differences وهو يساوي بالتقريب ضعف قيمة SED ويمكن حساب قيمته الدقيقة من خلال المعادلة التالية: LSD = qt(0.975, Residual df) * SEDتنبع أهمية المقدار LSD من حقيقة أن تحليل التباين يخبرنا فقط إن كانت هناك فروقات معنوية ما بين الفئات المدروسة للمعاملة أم لا، دون أن يوضح أي من تلك الفئات متشابهة وأيها مختلفة، لذا يمكننا استخدام قيمة LSD للمقارنة ما بين المتوسطات المحسوبة لكل واحدة من هذه الفئات، فإن زاد الفرق ما بين متوسطي فئتين عن قيمة LSD نستنتج وجود فروقات معنوية ما بين هاتين الفئتين، وإن لم يكن كذلك فالفارق ما بين متوسطي هاتين الفئتين لا يتجاوز حدود الخطأ المقاس بحسب المعطيات المدروسة. كما وجدنا سابقا فإن تحليل التباين قد أظهر لنا بما لا يدع مجالا للشك أن هناك فروقا معنوية بالزمن اللازم لقطع الربع ميل الأول ما بين الفئات الثلاث لمحركات السيارات بحسب عدد إسطواناتها، لكنه كما أوضحنا يقف عند هذا الحد ولا يخبرنا أي الفئات متشابهة وأيها مختلفة، فهذه الفروق التي نجدها بين المتوسطات المحسوبة قد تكون معنوية وقد تكون ضمن هامش خطأ التجربة! فليست كل السيارات التي تدفعها محركات بأربعة إسطوانات تقطع الربع ميل الأول خلال 19.1 ثانية فهناك تباين فيما بين السيارات ضمن هذه الفئة، بمعنى أن بعضها قد يكون أسرع قليلا من هذا الزمن وبعضها الآخر أبطئ، والمتوسط المعروض ما هو إلا تمثيل لمركز المجموعة، ومعنوية الفروق التي ظهرت نتيجة تحليل التباين السابق تعني أنه لدينا على الأقل فئة واحدة تختلف عن باقي الفئات، ولا تشترط أن تكون جميع تلك الفئات مختلفة معنويا عن بعضها البعض مثنى مثنى. لذا فإن الخطوة التالية بعد اكتشاف وجود فروقات معنوية هو إجراء مقارنات متعددة Multiple Comparison لكل فئات المعاملة الممكنة مثنى مثنى وتقرير أيها معنوي وأيها لا تتجاوز الفروقات الظاهرة بين متوسطاته هامش خطأ التجربة، لإنجاز ذلك لدينا العديد من الاختبارات الممكنة أحدها يدعى اختبار Tukey وهو ما سنوضح طريقة استخدامه فيما يلي: > mc <- TurkeyHSD(model, "cyl", ordered=TRUE) > mc Turkey multiple comparisons of means 95% family-wise confidence level factor levels have been ordered Fit: aov(formula = qsec ~ cyl) $cyl diff lwr upr p adj 4-6 1.205000 -0.4983980 2.908398 0.2053353 4-8 2.365130 0.8825122 3.847748 0.0013300 4-6 1.160130 -0.6190113 2.939271 0.2574564 يوضح الجدول الناتج جميع الأزواج الممكنة بين فئات المعاملة cyl الثلاث، موضحا إلى جانب كل منها الفرق ما بين متوسطات تلك الفئات ضمن العمود diff، وهنا أرغب بالتذكير أننا لا نتعامل في الإحصاء مع حقائق مطلقة ومثبتة لا تقبل الشك، بل نتعامل مع متوسطات وهوامش خطأ وعدم يقين، لذلك وإن كان الفرق بين متوسطي الزمنين اللازمين لقطع مسافة الربع ميل للسيارات بمحركات ذات ستة وثمانية إسطوانات هو 1.2 ثانية تقريبا، إلا أن هذا التقدير يحتمل هامشا من الخطأ يحدده إختبار Tukey بحدين أدنى lwr وأعلى upr يتراوح بين ناقص 0.5 ثانية (أي إحتمال وجود سيارة بمحرك ذي ستة إسطوانات أسرع بنصف ثانية من سيارة أخرى بمحرك ذي ثمانية إسطوانات) و 2.9 ثانية تقريبا لصالح السيارات بمحركات ذات ثمانية إسطوانات، ونرى في هذه الحالة وجود تداخل ما بين هاتين الفئتين من السيارات، لذا لا نستطيع الجزم بأن الفروقات التي رأيناها ما بين متوسطي الفئتين تعد معنوية، وهو ما يوضحه العمود الأخير الذي يمثل احتمال تشابه هاتين الفئتين المدروستين وهو في هذه الحالة 0.2 تقريبا أي 20% وبالتالي هو إحتمال أعلى من أن يتم تجاهله وبالتالي رفض فرضية التشابه. في اختبار Tukey نعتبر أن الفئتين المدروستين يوجد بينهما فروق معنوية حينما تكون قيمة الاحتمال الوارد في العمود الأخير للزوج المعني لا تتجاوز 0.05 (أي أن هامش الخطأ لا يتجاوز 5%)، وحينها سنجد أن المجال المحصور ما بين القيمتين lwr و upr لا يتضمن الصفر بين حديه، وهي الحال بين فئتي السيارات المزودة بمحركات ذات أربع وثمانية إسطوانات، حيث أن فرق الزمن بين متوسطيهما يتجاوز 2.3 ثانية، وهو يقارب في حدوده الدنيا 0.9 ثانية ويمكن أن يصل في حدوده العظمى إلى 3.8 ثانية تقريبا، كما أن إحتمال التشابه في هذه الحالة هو في حدود 0.001 أي 0.1% تقريبا، وبالتالي عملا بإسلوب نقض الفرض نقر بأن هاتين الفئتين غير متشابهتين وبالتالي هناك فروق معنوية فيما بينهما. يمكن عرض نتائج إختبار Tukey للمقارنات المتعددة بشكل رسومي يسهل قراءته وذلك باستخدام الأمر التالي: plot(mc) حيث أن الزوج الذي يتقاطع فيه محور العينات (أي عند القيمة 0 على محور السينات، وهو الخط المنقط الظاهر على المخطط) مع الخط الممثل لذلك الزوج والذي يحدد المجال بين قيمتي الحد الأدنى والأعلى يشير إلى عدم وجود فروق معنوية بين قطبيه. إن قيمة الخطأ المعياري SE, Standard Error المرتكب في حساب المتوسطات هو مقدار له ذات واحدة قياس القيم المقروءة والمتوسطات المحسوبة، لذا يصعب علينا تحديد مدى هامشية أو فداحة تلك الأخطاء من مجرد النظر إلى مقدار SE، فعشر غرامات خطأ في قياس الوزن عند البقال تكاد لا تذكر في حين أنها عند الجواهرجي كارثية، لذا عادة ما نقوم بحساب معامل الاختلاف CV%, Coefficient of Variation وهو كما نرى نسبة مؤية مستقلة عن واحدات القياس وتحسب من ناتج قسمة الجذر التربيعي لقيمة Mean Sq الخاصة بالقيم المتبقية Residuals على المتوسط العام، أي أنه في حالتنا هذه يمكن حساب قيمة معامل الاختلاف CV% بالطريقة التالية: > CV <- sqrt(2.2201) / 17.84875 > CV [1] 0.08347924 أي أن معامل الإختلاف في هذه الحالة هو في حدود 8.3% (بعد أن نضرب العدد الناتج بـ 100). وهكذا أصبحنا قادرين على التعبير عن الخطأ نسبة للمقادير التي نقيسها بمتوسطاتنا. لائحة المراجع: http://www.r-project.org.http://tryr.codeschool.com.http://www.statmethods.net.http://www.r-tutor.com.
  7. تعد لغة R من اللغات التي صعد نجمها حديثا وبشكل سريع بمجال البرمجة العلمية في قطاعي الإحصاء والمعلوماتية الحيوية (bioinformatics) حيث باتت معتمدة على نطاق واسع في كثير من الجامعات ومراكز البحث العلمية، وأصبحنا نرى استخدامها والإشارة إليها في المقالات المنشورة بالمجلات العلمية المحكّمة يزداد بشكل طردي ومتسارع، هذا عدى عن حقيقة كونها لغة حرة مفتوحة المصدر يخضع توزيعها لترخيص GPL الشهير. كل ذلك أدى إلى تزايد ما هو متوفر ومتاح على الشابكة (الإنترنت) من مصادر لها على توزع طيف تلك المصادر، فهناك الكتب الإلكترونية والدروس التعليمية وحتى المناهج الأكاديمية والدورات التدريبية إضافة إلى البرامج الجاهزة والمكتوبة بلغة R لتنفيذ هذه المهمة أو تلك، حتى أنها باتت تحظى ببعض الامتياز مقارنة بالعديد من العمالقة في قطاع البرمجة الرياضياتية العلمية والإحصائية مثل SAS و SPSS خصوصا في مجال توافر الجديد من الطرق والخوارزميات الحديثة، حيث يقاد هذا التوجه في معظمه من طرف الجامعات ممثلة بطلاب الدراسات العليا يحفّزهم على ذلك سهولة بناء الإضافات لهذه اللغة، ويعتبر هذا الأسلوب رغم ما قد يشوبه من نقاط ضعف تتعلق بموثوقية وجودة وغزارة تلك الإضافات الجديدة، والتي تتبع خبرة ومهارة مطوريها وناشريها، لكنها تبقى في القطاع العلمي والأكاديمي أفضل كثيرا من البدائل التجارية التي يعيبها ارتفاع ثمنها من جهة، ومن جهة أخرى بطئ إضافة التحديثات التي تعكس تطور القطاعات العلمية المختلفة، حيث أنها عادة ما تتبع دورة تجارية تتحكم بها الشركات المنتجة. سنحاول في هذه المقالة أن نقدم مدخلا مبسطا ومختصرا لأساسيات هذه اللغة ونستكشف بعضا من إمكانياتها واستخداماتها، والتي أتمنى أن أراها تدرّس في جامعاتنا يوما ما، بحيث تستخدم كأداة للاختبار والتجربة والتطوير ضمن الجلسات العملية لبعض المقررات العلمية في الكليات ذات الاختصاص. هذا هو الجزء الأخير في سلسة مؤلفة من أربع مقالات تهدف إلى التعريف بلغة R حيث قدم الجزء الأول مدخل عام إلى هذه اللغة بما فيها الإحصائيات الوصفية، أما الجزء الثاني فتحدث عن كيفية توليد بعض المخططات البيانية الإحصائية بلغة R، أما الجزء الثالث فتحدثنا فيه عن طريقة إجراء بعض التحاليل الإحصائية باستخدام هذه اللغة. للتذكير فقط، تستطيع أن تقوم بتحميل لغة R من الموقع الرسمي لها على الرابط http://www.r-project.org، وعملية تنصيب هذه اللغة تخلو من التعقيدات وبانتهاءها يمكنك تشغيل سطر الأوامر الخاص بها من خلال النقر على أيقونة اللغة على سطح المكتبة، وكل مانكتبه تاليا يكون داخل سطر الأوامر هذا، علما أننا نستخدم في كل أمثلتنا إطار البيانات المدعو mtcars والذي يأتي محزوما مع اللغة بشكل إفتراضي، وللحصول على معلومات إضافية عن طبيعة محتوى هذه البيانات يمكنك كتابة الأمر التالي في سطر الأوامر mtcars? ولاختصار طريقة الوصول إلى المعلومات ضمن إطار البيانات ننفذ الأمر (attach(mtcars فنصبح قادرين على استخدام التسمية mpg بدلا من استخدام الطريقة المفصلة mtcars$mpg للدلالة على عدد الأميال المقطوعة بغالون البنزين الواحد. عندما لا تكون المقادير المراد إختبارها كميّة متدرجة كما سبق وأن شاهدنا في تحاليل سابقة مثل إختبار t، بل هي قيم نوعية كحالة أنواع محركات السيارات من حيث عدد الإسطوانات cyl وارتباطها بنوع ناقل الحركة am هل هو أوتوماتيكي أم عادي، طبعا الغاية هي معرفة هل هناك فروق معنوية ما بين الفئات المختلفة للحركات من حيث عدد إسطواناتها، لمثل هكذا حالات عليك استخدام اختبار إحصائي يدعى باختبار chi-squared والمثال التالي يوضح كيفية تحضير بياناتك لهذا النوع من التحليل مستخدمين الدالة table حيث عرضنا في التعليمة التالية كيف سيظهر ناتج تنفيذ تلك الدالة على بياناتنا فقط لتوضيح شكل الجدول المطلوب تمريره للدالة chisq.test التالي والذي يقوم بتنفيذ الاختبار المقصود. كما جرت العادة فإن ما يهمنا من هذا الخرج هو قيمة p-value والتي تشير إلى إحتمال المصادفة (بمعنى أنه لاتوجد فروقات معنوية ما بين الفئات المختلفة وما يظهر لدينا من فروقات هي في هامش خطأ التجربة)، في المثال السابق قيمة p-value هي 0.01265 أي ضمن الحد المسموح به عادة للقبول بوجود فروق معنوية وهو 5% (أي 0.05)، وبالتالي فالفروق الملاحظة معنوية وموجودة، بمعنى أن نسبة السيارات ذات ناقل الحركة الأوتوماتيكي am=1 هي أكبر في حالة السيارات ذات عدد الإسطوانات الكبير مقارنة بتلك التي لديها محركات تحتوي على أربع اسطوانات فقط. ولمعرفة كم سيكون عدد السيارات ذات علبة التروس اليدوية أو الأوتوماتيكية في كل فئة من فئات المحركات الثلاث المصنفة بحسب عدد الإسطوانات وذلك في حال كان التوزع متساويا والفروقات غير موجودة نستخدم الدالة التالية: chisq.test(myTable)$expectedلننتقل إلى أداة أخرى تتيح لنا استكشاف جملة البيانات التي بين أيدينا وما فيها من علاقات وارتباطات وذلك من خلال شكل واحد يتضمن خريطة حرارية مضاف لها شجرتي عنقدة هرمية لكل من أعمدة البيانات التي لدينا (الصفات المدروسة مثل الوزن wt وعدد إسطوانات المحرك cyl وعدد الأميال المقطوعة بغالون البنزين الواحد mpg) وأسطر البيانات (وهي في حالتنا تمثل أنواع السيارات المدروسة مثل Toyota Corona و Honda Civic وغيرهما)، إن التعليمة التي نتحدث عنها هنا هي تعليمة heatmap لكن العقبة التي تقف في طريقنا هي نوع بيانات الدخل لهذه التعليمة، فهي لا تقبل إطار البيانات إنما هي بحاجة إلى بيانات محزومة على شكل مصفوفة! لا تقلق من هكذا عقبة، فهناك طيف كامل من التعليمات بلغة R مهمتها التحويل فيما بين صيغ وتنسيقات البيانات المختلفة، ولجميعها الصيغة التالية: y <- as.*(x)حيث x هي البيانات بتنسيقها الأصلي و y هي ذات البيانات بعد تحويلها إلى التنسيق المطلوب حيث يستعاض عن رمز النجمة * (في الصيغة الموضحة أعلاه) بالتنسيق الهدف والمطلوب التحويل إليه، فمثلا نجد مجموعة التعليمات التالية: (as.null(x و (as.numeric(x و (as.character(x و (as.factor(x الخ... وفق ذات الأسلوب، لدينا طقم آخر من التعليمات غايته التحقق إن كانت صيغة متحول ما تتبع تنسيقا بعينه أم لا، وتلك التعليمات تعيد القيمة المنطقية true إن كان المتحول يطابق التنسيق الخاص بالتعليمة فيما تعيد القيمة المنطقية false في بقية الحالات، حيث تجد على سبيل المثال مجموعة التعليمات التالية متاحة لك للاستخدام وهي: (is.null(x و(is.numeric(x و(is.character(x و (is.factor(x الخ... حسنا، لكن كيف سنستفيد من كل هذه المعلومات في حالة مثالنا المتعلق باستخدام تعليمة heatmap والتي تحتاج كدخل لها بيانات بتنسيق matrix وليس data.frame كما سبق وأن ذكرنا، للقيام بذلك سنستخدم التعليمة التالية لتحويل إطار بيانات mtcars الذي نستخدمه في مثالنا إلى تنسيق المصفوفة ونحفظه ضمن متحول جديد أسميناه للسهولة x وبعدها مررنا تلك المصفوفة x إلى تعليمة heatmap لنحصل على النتيجة الموضحة في الشكل التالي: x <- as.matrix(mtcars); heatmap(x, scale=”column”); من البديهي في الخريطة الحرارية الاستنتاج بأن النقاط التي تتقارب ألوانها في هذا المخطط تعود إلى قراءات متقاربة في القيمة ضمن البيانات التي استخدمت في توليد ذلك المخطط، كذلك فإن الأغصان التي تتلاقى مبكرا ضمن كل من شجرتي العنقدة الهرمية سواء للصفات (أعلى الرسم) أو السيارات (على يسار الرسم) تشير إلى تشابه أكبر من تلك التي تتلاقى في أماكن أبعد. نستطيع في لغة R كما في أي لغة برمجة أخرى أن نعرف توابعنا الخاصة ومن ثم نستدعيها، والمثال التالي يوضح حالة نموذجية بسيطة سنشرحها سطرا بسطر وبشكل مقتضب، حيث سنقوم بتعريف تابع جديد سندعوه SEM لحساب الخطأ المعياري المرتكب في حساب قيمة المتوسط، وهو للمصادفة الغريبة تابع غير موجود ضمن مجموعة توابع لغة R الأساسية! إن حساب تلك القيمة الإحصائية بسيط نسبيا فهي ناتج تقسيم الإنحراف المعياري على جذر عدد القراءات منقوصا منه واحد، لنلقي نظرة الآن على الشيفرة البرمجية التي نقوم من خلالها بتعريف هذا التابع: SEM <- function(x, na.rm = TRUE) { if (na.rm == TRUE) VAR <- x[!is.na(x)] else VAR <- x; SD <- sd(VAR); N <- length(VAR); SE <- SD/sqrt(N - 1); return(SE); }كما نلاحظ في السطر الأول فقد قمنا بتحديد اسم التابع قبل رمز الإسناد، أما ما يتلو رمز الإسناد فهو تصريح بأن ما نقوم بتعريفه هنا ما هو إلا تابع له وسيطين دعونا الأول x والذي يفترض به أن يتضمن شعاع القيم التي نرغب بحساب الخطأ المعياري المرتكب في حساب متوسطها، أما الثاني فدعوناه na.rm وهو وسيط اختياري بحسب الصيغة الموضحة أعلاه وقيمته الافتراضية هي TRUE وسنستخدمه لمعرفة إن كان المستخدم يريد تضمين أم حذف القيم غير المحددة أي القيم المفقودة، ومن ثم نرى القوس الكبير قد فتح ليقوم بحزم مجموعة التعليمات التي تنتمي إلى هذا التابع. السطر التالي مباشرة يتأكد من اختيار المستخدم بالنسبة لطريقة التعامل مع القيم المفقودة، فإن كان يرغب بحذفها نقلنا إلى المتحول الداخلي VAR فقط تلك القيم من x والتي ليست غير محددة أو مفقودة، وإلا فإن قيمة المتحول الداخلي VAR ستتضمن كامل قيم الشعاع x (وضعنا الأمر بهذه الصيغة لتوضيح آلية استخدام العبارات الشرطية والوسطاء ذات القيم الاختيارية، لكن الصواب في هذه الحالة بالذات هو أننا نقوم دوما باستثناء القيم الغير محددة فحساب قيمتنا غير ممكن بوجودها). بعد ذلك نقوم بحساب الانحراف المعياري للقيم التي باتت موجودة الآن في المتحول VAR وذلك من خلال استخدامنا للتابع sd ونحفظ الجواب الناتج بمتحول جديد ندعوه SD (تذكر أن لغة R حساسة لحالة الأحرف كبيرة كانت أم صغيرة بمعنى أنها تميز فيما بينها). أما في السطر التالي فنقوم بإيجاد عدد العناصر الموجودة بشعاع القيم VAR ومن ثم نحفظ ذلك العدد ضمن متحول جديد ندعوه N. وهكذا أصبحنا جاهزين لحساب قيمة الخطأ المعياري المرتكب في حساب متوسط مجموعة القيم هذه وذلك من خلال إجراء عملية القسمة لقيمة الانحراف المعياري على الجذر التربيعي لعدد القراءات بعد أن أنقصناه بمقدار 1، حينها نحفظ الجواب الناتج في متحول جديد دعوناه في مثالنا SE، لتأتي بعدها الخطوة الأخيرة باستخدامنا للأمر return ليعيد الجواب الناتج إلى من استدعى هذا التابع، ونختم أخيرا بإغلاق القوس الكبير الذي استخدم لحزم مجموعة التعليمات هذه رابطا إياها باسم التابع الذي صرحنا عنها بداية في السطر الأول. إن لغة R هي لغة مفتوحة المصدر إلى حد بعيد، فأي تابع تقوم بتعريفه مثل تابعنا الذي دعوناه SEM الوارد أعلاه، يستطيع المستخدم الاطلاع على شيفرته المصدرية كاملة بمجرد كتابة اسمه دون أي زيادة أو إضافات ومن ثم النقر على زر الإدخال، ليس هذا فحسب، بل حتى أنك تستطيع الإطلاع على كيفية كتابة التوابع الخاصة بلغة R نفسها دون كثير عناء، فعلى سبيل المثال إن كان لديك فضول لمعرفة طبيعة وتفاصيل الخوارزمية التي استخدمت في التابع cor لحساب قيمة معامل الارتباط أو التابع lm لحساب علاقة الانحدار وسواهما من التوابع الأخرى، فكل ما عليك القيام به هو كتابة اسم ذلك التابع دون أي إضافات أخرى ومن ثم النقر على زر الإدخال، لتقوم لغة R بعرض الشيفرة المصدرية الداخلية لذلك التابع كاملة أمامك. إن إحدى نقاط قوة لغة R هي سهولة توسعتها من خلال مجموعة الإضافات الهائلة المتاحة لها والتي قام بتطويرها الآلاف من الجامعات والمراكز العلمية وحتى الباحثين المستقلين وطلاب الدراسات العليا، يعينهم في ذلك السهولة النسبية في آلية بناء مثل تلك المكتبات أو الإضافة الجديدة لهذه اللغة، فهي لاتحتاج في أغلب الحالات إلى أي خبرات أو معارف خارج نطاق لغة R نفسها وهو أمر ممتع ومميز بحق، للإطلاع على لائحة الإضافات الرسمية المنشورة على موقع لغة R نفسها يمكنكم التحقق من هذا الرابط (ملاحظة: لقد اخترنا مخدم موجود في روسيا الاتحادية لضمان الوصول إليه بسهولة دون أي حجب!): أما لمن لديه فضول التعرف على آلية بناء مكتبته أو إضافته الخاصة فأحيله إلى هذا المرجع السهل والمميز. من الإضافات المميزة التي أنصحك قارئي العزيز بالإطلاع عليها هناك الإضافة ggplot2 والتي تفتح أمام مستخدمي لغة R آفاقا واسعة لتحسين وإثراء نوعية المخططات البيانية التي يمكن توليدها والحصول عليها، وهذه الإضافة هي إضافة ذائعة الصيت حتى أن هنالك كتب كاملة تتحدث عنها وعن مزاياها وإمكانياتها، كذلك نذكر الإضافة doSMP على سبيل المثال والتي قد تكون واحدة من الإضافات الأولى التي ترغب بالتعرف عليها إن كنت تطمح لقرع باب الحوسبة التفرعية، فهي أداة بسيطة تستطيع من خلالها تحويل بنى الحلقات البسيطة إلى نسخة تفرعية تستثمر كامل طاقة نوى المعالج أو المعالجات التي لديك (حيث أن المعالجات الثنائية والرباعية النوى أصبحت شائعة في الأسواق هذه الأيام، والتوجه العام هو نحو زيادة عدد النوى المتاحة على شريحة معالج واحد). أخيرا وليس آخرا، تجدر الإشارة إلى أداة مميزة أخرى تدعى RExcel والتي تسمح للغة R أن تعمل بالتكامل مع تطبيق Microsoft Excel ذائع الصيت وواسع الانتشار للجداول الممتدة، فهي تمكن المستخدم من نقل البيانات من برنامج Excel إلى لغة R وبالعكس، هذا عدى عن تمكين مستخدمي برنامج Excel من استدعاء توابع لغة R المختلفة وتنفيذها على ما لديهم من بيانات مباشرة كما لو كان التعامل يتم مع أي تابع معتاد ضمن برنامج Excel، حيث سيتم تنفيذ التحليل باستخدام لغة R ومن ثم إعادة النتيجة إلي برنامج Excel بشكل مباشر وشفاف ليتم عرضها في إحدى الخلايا دون كثير عناء من قبل المستخدم. لا يخلو تنصيب هذه الأداة يدويا من بعض التعقيد لكثرة ما فيها من مكونات وما تحتاج إليه من ضبط وإعداد، لكن أسهل طريقة للحصول عليها جاهزة للعمل هي من خلال تنصيب RAndFriendsSetup والتي تستطيع الحصول عليها من خلال هذا الرابط: http://rcom.univie.ac.at. في ختام هذه السلسلة من المقالات، نحن نعي تماما أن ما قمنا به لا يتجاوز خدشنا لسطح المعرفة العميق بهذا المجال من العلوم سواء على صعيد الإحصاء أو لغة R ذاتها، لكنها مقدمة متواضعة نضعها بين أيدي المهتمين لينطلقوا منها ويبنوا عليها وصولا إلى نضج أعمق وإغناء أفضل لهذا الموضوع، وقد تجاوزنا في هذه السلسلة من المقالات عن تناول بعض المواضيع الشيقة التي ترتبط بهذا السياق وذلك سعيا منا وراء التبسيط والسهولة نظرا لأن هدفنا الأصلي كان تقديم مجموعة من المقالات التي تمثل مدخلا للغة R، وبالتالي فإن مناقشة أي موضوع يتسم بالتعقيد قد يضر بهذا الهدف والغاية، لكني قد أعود لاحقا للكتابة عن بعضها وأخص بالذكر هنا مناقشة موضوع تحليل التباين ANOVA شائع الصيت بين كل من خاض بمزيد من التفصيل في علم التحليل الإحصائي، لذا ترقبوا منا كل جديد. لائحة المراجع: http://www.r-project.orghttp://www.statmethods.nethttp://www.r-tutor.com
  8. تعد لغة R من اللغات التي صعد نجمها حديثا وبشكل سريع بمجال البرمجة العلمية في قطاعي الإحصاء والمعلوماتية الحيوية (bioinformatics) حيث باتت معتمدة على نطاق واسع في كثير من الجامعات ومراكز البحث العلمية، وأصبحنا نرى استخدامها والإشارة إليها في المقالات المنشورة بالمجلات العلمية المحكّمة يزداد بشكل طردي ومتسارع، هذا عدى عن حقيقة كونها لغة حرة مفتوحة المصدر يخضع توزيعها لترخيص GPL الشهير. كل ذلك أدى إلى تزايد ما هو متوفر ومتاح على الشابكة (الإنترنت) من مصادر لها على توزع طيف تلك المصادر، فهناك الكتب الإلكترونية والدروس التعليمية وحتى المناهج الأكاديمية والدورات التدريبية إضافة إلى البرامج الجاهزة والمكتوبة بلغة R لتنفيذ هذه المهمة أو تلك، حتى أنها باتت تحظى ببعض الامتياز مقارنة بالعديد من العمالقة في قطاع البرمجة الرياضياتية العلمية والإحصائية مثل SAS و SPSS خصوصا في مجال توافر الجديد من الطرق والخوارزميات الحديثة، حيث يقاد هذا التوجه في معظمه من طرف الجامعات ممثلة بطلاب الدراسات العليا يحفّزهم على ذلك سهولة بناء الإضافات لهذه اللغة، ويعتبر هذا الأسلوب رغم ما قد يشوبه من نقاط ضعف تتعلق بموثوقية وجودة وغزارة تلك الإضافات الجديدة، والتي تتبع خبرة ومهارة مطوريها وناشريها، لكنها تبقى في القطاع العلمي والأكاديمي أفضل كثيرا من البدائل التجارية التي يعيبها ارتفاع ثمنها من جهة، ومن جهة أخرى بطئ إضافة التحديثات التي تعكس تطور القطاعات العلمية المختلفة، حيث أنها عادة ما تتبع دورة تجارية تتحكم بها الشركات المنتجة. سنحاول في هذه المقالة أن نقدم مدخلا مبسطا ومختصرا لأساسيات هذه اللغة ونستكشف بعضا من إمكانياتها واستخداماتها، والتي أتمنى أن أراها تدرّس في جامعاتنا يوما ما، بحيث تستخدم كأداة للاختبار والتجربة والتطوير ضمن الجلسات العملية لبعض المقررات العلمية في الكليات ذات الاختصاص. هذا هو الجزء الثالث في سلسة مؤلفة من أربع مقالات تهدف إلى التعريف بلغة R حيث قدم الجزء الأول مدخل عام إلى هذه اللغة بما فيها الإحصائيات الوصفية، أما الجزء الثاني فتحدث عن كيفية توليد بعض المخططات البيانية الإحصائية بلغة R، فيما سنختم السلسلة بجزء رابع يتحدث عن بعض التقنيات المتقدمة في هذه اللغة. للتذكير فقط، تستطيع أن تقوم بتحميل لغة R من الموقع الرسمي لها على الرابط http://www.r-project.org، وعملية تنصيب هذه اللغة تخلو من التعقيدات وبانتهاءها يمكنك تشغيل سطر الأوامر الخاص بها من خلال النقر على أيقونة اللغة على سطح المكتبة، وكل مانكتبه تاليا يكون داخل سطر الأوامر هذا، علما أننا نستخدم في كل أمثلتنا إطار البيانات المدعو mtcars والذي يأتي محزوما مع اللغة بشكل إفتراضي، وللحصول على معلومات إضافية عن طبيعة محتوى هذه البيانات يمكنك كتابة الأمر التالي في سطر الأوامر mtcars? ولاختصار طريقة الوصول إلى المعلومات ضمن إطار البيانات ننفذ الأمر (attach(mtcars فنصبح قادرين على استخدام التسمية mpg بدلا من استخدام الطريقة المفصلة mtcars$mpg للدلالة على عدد الأميال المقطوعة بغالون البنزين الواحد. كل ما سبق ذكره من دوال يندرج تحت مظلة ما يدعى بالإحصائيات الوصفية العامة والتي تتعلق بشعاع معين من القيم، أما الدالة cor(x, y) فهي تحسب مقدار معامل الارتباط بين شعاعين من القيم هما في هذه الحالة x و y (أو بين عمودين في حالة البيانات المستوردة من ملف ما)، حيث تتدرج قيمة معامل الارتباط من -1 حتى +1 وتشير القيم الموجبة إلى وجود إرتباط طردي يزداد وضوحا كلما اقترب من +1، أي أنه كلما زادت قيمة x رافقها زيادة في قيمة y، فيما تشير القيمة السالبة لمعامل الارتباط إلى وجود ارتباط أيضا لكنه في هذه الحالة عكسي ويزداد وضوحا كلما اقترب من -1، أي أن قيمة x تزداد بتناقص y والعكس صحيح، في حين تشير قيمة معامل الارتباط التي تقترب من الصفر إلى أن تغير قيمة x لا يظهر أي علاقة بتغير قيمة y المقابلة. مع ذلك عليك كباحث أن تجد علاقة سببية بين x و y قبل أن تلجئ إلى حساب معامل الارتباط واعتماد ما تحصل عليه من نتائج، فإن كانت x تشير على سبيل المثال إلى عدد سكان مدينة دمشق خلال السنوات العشرين الماضية، فيما تشير yإلى عدد السيارات في مدينة حلب خلال نفس الفترة الزمنية، فإن قيمة معامل الارتباط إن تم حسابه سوف تشير إلى وجود ارتباط إيجابي طردي واضح، وهو شيء طبيعي! فعدد سكان دمشق في ازدياد وكذلك عدد السيارات في مدينة حلب، لكن هل لهذا الارتباط الطردي المحسوب هنا أي معنى سببي؟ من الواضح أن الجواب هو لا، لذا عليك توخي الحذر عند استخدام الأساليب والطرق الإحصائية. لننتقل الآن إلى استعراض مجموعة من الاختبارات الإحصائية وكيفية تنفيذها باستخدام لغة R. دعونا نبدأ باختبار معامل الارتباط والذي سبق وأن رأينا دالة cor البسيطة التي تحسب قيمته، لكنها تبقينا في التباس إحصائي، فإن حصلنا على سبيل المثال على الناتج 0.3 فهل سنقول بأن هناك إرتباط لكنه ضعيف؟ أم ننفي وجود مثل هذا الارتباط ونقبل أن مقدار معامل الارتباط قريب إلى 0 وبالتالي فهو غير معنوي أي غير موجود؟ في حقيقة الأمر هناك اختبار يحسب مدى إحتمالية الحصول على مقدار ما لمعامل الارتباط عن طريق المصادفة البحتة دون أن يكون هناك إرتباط حقيقي أو فعلي، وعادة ما يقبل في مجال الإحصاء إعتبار الحد 0.05 (أي 5%) هو الحد الأقصى المسموح به من الشك، فإن كان احتمال المصادفة أقل من 0.05 رفضنا فرضية المصادفة وبالتالي فالارتباط موجود ومعنوي (أي أننا نعمل هنا بأسلوب نقض الفرض)، وإلا فإننا لا نستطيع إثبات ذلك كون الشكوك في إحتمال المصادفة أكبر من أن يتم إهمالها أو التغاضي عنها. لتجريب ذلك دعونا بداية نختبر حساب معامل الارتباط ما بين وزن السيارة من جهة والمسافة التي تقطعها بالأميال لكل غالون من البنزين، ويتم ذلك مباشرة من خلال الأمر (cor(wt, mpg وسيكون الناتج في هذه الحالة هو -0.87 أي أن طبيعة تلك العلاقة هي عكسية واضحة. أما لتنفيذ الاختبار المفصل لمعامل الارتباط، فعلينا حينها استخدام الأمر البديل التالي (cor.test(wt, mpg ليظهر الناتج كما هو موضح في الشكل التالي والذي يتضمن أيضا إختبار وجود أي إرتباط ما بين وزن السيارة من جهة والزمن اللازم لقطع مسافة ربع ميل. لتفسير ما حصلنا عليه من نتائج علينا مراقبة القيمة المحسوبة للمقدار p-value والتي تشير إلى احتمال كون قيمة معامل الارتباط التي لدينا قد ظهرت بالمصادفة وأن هذا الارتباط الذي نتحدث عنه غير موجود أصلا، ففي الحالة الأولى قيمة هذا الاحتمال صغيرة جدا إذ تبلغ 1.294e-10 (وهي معروضة بصيغة التمثيل العلمي للأرقام الكبيرة أو الصغيرة، وفي حالتنا هذه يساوي 1.294 x 10^-10 أو 1.294 مقسوما على عشرة بالأس عشرة). أما في الحالة الثانية، فعلى الرغم من أن قيمة معامل الإرتباط هي -0.175 إلا أن احتمال المصادفة في الحصول على هذه القيمة لمعامل الارتباط بالنسبة لمجموعة البيانات المدروسة (أي p-value) هو 0.3389 أي تقريبا %34 وهو هامش شك كبير يصعب تجاهله، لذا من وجهة النظر الإحصائية لا يعد ذلك الارتباط معنويا أو موجودا أصلا. يمكننا أيضا تطبيق دالة الارتباط على كامل إطار البيانات بكل ما فيه من أعمدة بحيث تحفظ النتائج ضمن مصفوفة تعرض فيها قيم معامل الارتباط ما بين كل زوجين ممكنين من الأعمدة مثنى مثنى بشكل مشابه لما نحصل عليه في النسخة الرسومية من تلك الأزواج والتي تنتج عند تطبيق الدالة pairs، وللقيام بذلك يمكنك تنفيذ الأمر التالي: (cor(mtcars. هناك إختبار إحصائي آخر مفيد وبسيط هو إختبار t يستخدم عادة لتحديد ما إذا كانت مجموعتان من العينات أو القراءات تنتميان لذات المجتمع الإحصائي، بمعنى أنهما تمتلكان ذات الصفات والمقومات الإحصائية، وبالتالي لا دليل إحصائي يمكنه التمييز فيما بينهما، أي أنه يختبر الفروق الظاهرة بين المجموعتين هل هي معنوية لدرجة يمكننا معها التفريق بينهما أم لا، إن ناتج هذا الاختبار كما هو حال الإختبار السابق والعديد غيرها من الإختبارات الإحصائية يعطى على شكل قيمة تمثل مقدار احتمال ما يدعى بفرضية العدم، وفي حالتنا هذه تنص فرضية العدم على نفي وجود فروق معنوية ما بين مجموعتي العينات أو القراءات قيد الدراسة، فإن كانت قيمة هذا الإحتمال 0.05 فما دون، رفضنا نظرية العدم وقبلنا بأن ما نراه من فروقات ليس مجرد مصادفة بل هو دليل على أن الفروقات ما بين هاتين المجموعتين من البيانات معنوية في هامش خطأ لا يتجاوز 5% وهي العتبة الإحصائية المقبولة عادة (في بعض الدراسات كالحالات المخبرية أو الطبية قد يجري التشدد أكثر فلا نقبل بأكثر من 1% كهامش للخطأ أو ما هو دون ذلك). سنقوم بداية بتقسيم بيانات الزمن اللازم لقطع مسافة ربع ميل والتي لدينا في إطار البيانات mtcars إلى ثلاث مجموعات على أساس عدد اسطوانات المحرك cyl (المجموعة a للسيارات ذات 4 اسطوانات، والمجموعة b للسيارات ذات 6 اسطوانات، وأخيرا المجموعة c للسيارات ذات 8 اسطوانات) وذلك بمعونة مجموعة التعليمات التالية بلغة R: a <- qsec[cyl == 4]; b <- qsec[cyl == 6]; c <- qsec[cyl == 8];يوضح المثالين التاليين إختبار t للمقارنة بين سيارات المجموعة a والمجموعة b من ناحية التسارع، ونلاحظ أن الفروقات بينهما غير معنوية! حيث أن احتمال المصادفة p-value هو %18 تقريبا (أي أنه يتجاوز حد %5 المعتمد عادة)، فمتوسط الزمن اللازم لقطع ربع ميل في الفئة الأولى هو تقريبا 19 ثانية، أما في المجموعة الثانية فهو 18 ثانية تقريبا. بعد ذلك قمنا بالمقارنة ما بين المجموعتين a و c لنجد أن الفروقات بينهما تصنف على أنها معنوية وذلك بحسب نتائج إختبار t حيث أن قيمة p-value هي تقريبا %0.1 مع متوسط زمن 19 ثانية للمجموعة الأولى و 16.75 ثانية للمجموعة الثانية. من جهة أخرى وبمجرد تحديد وجود ارتباط معنوي ما بين أي مقدارين، علينا عندها توصيف ذلك الارتباط بشكل كمي بعد أن حددنا وجوده بشكل وصفي، وهذا ما يتم توصيفه من خلال علاقة الانحدار (Regression) ومثالها العلاقة الخطية البسيطة والتي يعبر عنها بمعادلة خط مستقيم من الشكل y = a + b x حيث a هو الثابت الذي يمثل قيمة y حينما تكون قيمة x = 0 في حين أن b تمثل ميل ذلك الخط المستقيم (أو نسبة تغير المقدار y من أجل تغير قيمة x بمقدار 1)، وتحسب هذه المقادير بحيث يمر الخط المستقيم من بين مجموعة النقاط (x, y) بشكل يجعل مقدار الخطأ أقل ما يمكن، حيث أن قيمة الخطأ في كل نقطة x مقاسة هي عبارة عن الفرق ما بين قيمة y الفعلية المقابلة وبين قيمة y المحسوبة من خلال علاقة الخط المستقيم التي حصلنا عليها في علاقة الإنحدار. إن أشكال علاقات الإنحدار يمكن لها أن تتدرج من البساطة (حيث قيمة y تحسب بدلالة متحول وحيد x1) إلى أشكال أكثر تعقيدا نستخدم فيها أكثر من متحول x لحساب قيمة y ( مثلا y = a + b x1 + c x2 + d x3)، كما أن علاقة الإنحدار تلك يمكن أن لا تكون خطية فحسب (وفيها تظهر x من الدرجة الأولى فقط) بل يمكن لها أن تتعدى إلى صيغ تربيعية أو تكعيبية أو سواها (مثلا y = a + b x + c x2 + d x3)، وللقيام بحساب تابع الإنحدار الخطي البسيط بلغة R نستخدم التعليمة التالية (fit <- lm(y ~ x، فمثلا في حال الرغبة في إيجاد تابع الإنحدار الخطي البسيط الذي يحسب المسافة المقطوعة بغالون البنزين الواحد بدلالة وزن السيارة نستخدم الأمر التالي: fit <- lm(mpg ~ wt);ويمكن عرض تفاصيل نتائج هذا الحساب الذي أجريناه للتو باستخدام الدالة summary العامة الأغراض بعد تمرير النموذج الذي تم حسابه باستخدام الدالة ()lm سابقة الذكر، وسيكون الناتج كما هو موضح أدناه: كذلك نستطيع عرض علاقة الإنحدار الخطي البسيطة هذه بشكل رسومي أيضا وذلك من خلال التعليمتين التاليتين: plot(wt, mpg); abline(fit);حيث تقوم دالة ()plot برسم المخطط البياني الذي يمثل وزن السيارات wt على محور السينات x فيما المسافة المقطوعة بغالون البنزين الواحد mpg يتم تمثيلها على محور العينات y، من جهة أخرى تقوم الدالة ()abline بإضافة ورسم الخط المستقيم الذي يوضح علاقة الإنحدار التي لدينا، وهي علاقة خطية بسيطة. بإمكانك تحسين ما يعرضه الشكل السابق من خلال إظهار أسماء موديلات السيارات لبعض النقاط المختارة من ذلك المخطط البياني من خلال استدعاء الدالة التالية: identify(wt, mpg, labels=rownames(mtcars));حيث يشير الوسيطين الأول والثاني إلى المقادير الممثلة على كل من محور السينات x ومحور العينات y على التوالي، فيما وظيفة الوسيط الثالث هي تحديد القيمة المراد عرضها لكل نقطة يتم اختيارها من نقاط المخطط البياني الظاهر أمامنا (حيث سيتغير شكل مشيرة الفأرة، وعند النقر على أي نقطة من نقاط المخطط البياني يتم إضافة تسمية قربها، ويستمر هذا السلوك إلى أن تنقر على زر Esc من لوحة المفاتيح)، وفي حالتنا هذه سنستخدم أسماء موديلات السيارات المتوافرة أصلا في إطار mtcars للبيانات على شكل تسميات للأسطر، وما تقوم به دالة rownames هنا هو استرجاع تلك الأسماء وتمريرها للوسيط labels في الدالة identify حتى تستخدمها. إن طريقة كتابة العلاقة في الدالة lm تحدد نوع تابع الإنحدار الذي يجري نمذجته، وما رأيناه في مثالنا السابق هو علاقة إنحدار خطية بسيطة حيث أن ترميز العلاقة المستخدم كان من الشكل y~x وهو يكافئ العلاقة الرياضية y=a+bx، قد نحتاج إلى بناء نموذج فيه تابع الإنحدار خطي بسيط لكن بدون الثابت (أي أن a=0 بمعنى أن y لا تمتلك قيمة عندما x=0)، في تلك الحالة نستخدم الترميز التالي للعلاقة في الدالة lm وهو y~x-1 والمكافئ الرياضي لهذه العلاقة هو y=bx، أما إن كانت علاقة الإنحدار خطية لكن ليست بسيطة، بمعنى أنه لدينا أكثر من متحول أو قيمة تؤثر في حساب y عندها نستخدم الترميز التالي y~x1+x2 وفي تلك الحالة يكون المكافئ الرياضي هو y=a+bx1+cx2، من جهة أخرى إن أردنا نمذجة علاقة إنحدار بسيطة لكن غير خطية فعلينا حينها استخدام الترميز التالي في الوسيط الذي سيتم تمريره للدالة lm وهو (y~x+I(x^2 وأعتقد أنك تستطيع تخمين المكافئ الرياضي لعلاقة الانحدار البسيطة غير الخطية هذه وهو y=a+bx+cx^2 بمجرد حساب علاقة الإنحدار، يمكننا استخدام النموذج الناتج لتوقع قيمة y بدلالة قيمة x المعطاة، فماذا ستكون المسافة المتوقع قطعها بغالون البنزين الواحد إن علمنا أن وزن السيارة هو 4.5 ألف ليبرة؟ لحساب ذلك نستخدم الدالة ()predict كما يلي (وسيكون الناتج هو 13.235 ميل تقريبا): predict(fit, list(wt = 4.5)); هذه هي نهاية الجزء الثالث من سلسلة المقالات التي تتحدث عن لغة R، انتظروا الجزء الرابع والذي سنتناول فيه بعض التطبيقات المتقدمة لهذه اللغة فإلى لقاء قريب. لائحة المراجع: http://www.r-project.orghttp://www.statmethods.nethttp://www.r-tutor.com
  9. تعد لغة R من اللغات التي صعد نجمها حديثا وبشكل سريع بمجال البرمجة العلمية في قطاعي الإحصاء والمعلوماتية الحيوية (bioinformatics) حيث باتت معتمدة على نطاق واسع في كثير من الجامعات ومراكز البحث العلمية، وأصبحنا نرى استخدامها والإشارة إليها في المقالات المنشورة بالمجلات العلمية المحكّمة يزداد بشكل طردي ومتسارع، هذا عدى عن حقيقة كونها لغة حرة مفتوحة المصدر يخضع توزيعها لترخيص GPL الشهير. كل ذلك أدى إلى تزايد ما هو متوفر ومتاح على الشابكة (الإنترنت) من مصادر لها على توزع طيف تلك المصادر، فهناك الكتب الإلكترونية والدروس التعليمية وحتى المناهج الأكاديمية والدورات التدريبية إضافة إلى البرامج الجاهزة والمكتوبة بلغة R لتنفيذ هذه المهمة أو تلك، حتى أنها باتت تحظى ببعض الامتياز مقارنة بالعديد من العمالقة في قطاع البرمجة الرياضياتية العلمية والإحصائية مثل SAS و SPSS خصوصا في مجال توافر الجديد من الطرق والخوارزميات الحديثة، حيث يقاد هذا التوجه في معظمه من طرف الجامعات ممثلة بطلاب الدراسات العليا يحفّزهم على ذلك سهولة بناء الإضافات لهذه اللغة، ويعتبر هذا الأسلوب رغم ما قد يشوبه من نقاط ضعف تتعلق بموثوقية وجودة وغزارة تلك الإضافات الجديدة، والتي تتبع خبرة ومهارة مطوريها وناشريها، لكنها تبقى في القطاع العلمي والأكاديمي أفضل كثيرا من البدائل التجارية التي يعيبها ارتفاع ثمنها من جهة، ومن جهة أخرى بطئ إضافة التحديثات التي تعكس تطور القطاعات العلمية المختلفة، حيث أنها عادة ما تتبع دورة تجارية تتحكم بها الشركات المنتجة. سنحاول في هذه المقالة أن نقدم مدخلا مبسطا ومختصرا لأساسيات هذه اللغة ونستكشف بعضا من إمكانياتها واستخداماتها، والتي أتمنى أن أراها تدرّس في جامعاتنا يوما ما، بحيث تستخدم كأداة للاختبار والتجربة والتطوير ضمن الجلسات العملية لبعض المقررات العلمية في الكليات ذات الاختصاص. هذا هو الجزء الثاني في سلسة مؤلفة من أربع مقالات تهدف إلى التعريف بلغة R حيث قدم الجزء الأول مدخل عام إلى هذه اللغة بما فيها الإحصائيات الوصفية، أما الجزء الثالث فسيتحدث عن كيفية إجراء بعض الاختبارات الإحصائية بلغة R، فيما نختم السلسلة بجزء رابع يتحدث عن بعض التقنيات المتقدمة في هذه اللغة. للتذكير فقط، تستطيع أن تقوم بتحميل لغة R من الموقع الرسمي لها على الرابط http://www.r-project.org، وعملية تنصيب هذه اللغة تخلو من التعقيدات وبانتهاءها يمكنك تشغيل سطر الأوامر الخاص بها من خلال النقر على أيقونة اللغة على سطح المكتبة، وكل مانكتبه تاليا يكون داخل سطر الأوامر هذا، علما أننا نستخدم في كل أمثلتنا إطار البيانات المدعو mtcars والذي يأتي محزوما مع اللغة بشكل إفتراضي، وللحصول على معلومات إضافية عن طبيعة محتوى هذه البيانات يمكنك كتابة الأمر التالي في سطر الأوامر mtcars? ولاختصار طريقة الوصول إلى المعلومات ضمن إطار البيانات ننفذ الأمر (attach(mtcars فنصبح قادرين على استخدام التسمية mpg بدلا من استخدام الطريقة المفصلة mtcars$mpg للدلالة على عدد الأميال المقطوعة بغالون البنزين الواحد. تبدأ أول خطوة من أي تحليل إحصائي باستكشاف ما لدينا من بيانات وذلك من خلال إلقاء نظرة سريعة على بعض المخططات البيانية والرسوم التوضيحية ذات الصبغة الإحصائية والتي عليها أن تقوم بتنفيذ تلك المهمة على أتم وجه، وسنمر في مقالتنا هذه على مجموعة من أهم وأشهر تلك المخططات البيانية الإحصائية محاولين تقديم شرح مختصر عن كل منها يصف طريقة توليده ويوضح ما يتم عرضه وطبيعة الفائدة منه. لدى لغة R تعليمة بسيطة بالصيغة لكنها في ذات الوقت تقدم خدمة عظيمة في إطار عرض ما لدينا من بيانات وتوضيح ما فيها من علاقات محتملة، تدعى هذه التعليمة pairs وتقبل كدخل لها إسم إطار البيانات الذي لدينا كاملا، لتقوم بعدها برسم مصفوفة من المخططات البيانية لكل زوج ممكن من هذه البيانات على شكل مخطط مبعثر (scatter plot) بحيث يظهر كل زوج في مخططين بيانيين يتبادلان فيه مكان التمثيل على المحورين x و y، يظهر الشكل التالي مثالا عن ناتج تنفيذ هذه التعليمة عند تطبيقها على إطار mtcars للبيانات: pairs(mtcars); هنالك ملاحظة أود ذكرها طالما أننا نتحدث عن الرسوم البيانية، فمعشر الإحصائيين لا يفضلون استخدام مخطط القطاعات الدائرية على عكس ما هو شائع في عالم المال والأعمال، ويفضلون بديلا عنها الخطوط البيانية أو حتى التمثيل بالأعمدة وذلك لأن الناس يستطيعون الحكم على الأطوال بشكل أكثر دقة من الأحجام، خصوصا عندما تكون القيم متقاربة. أما لرسم مخطط مبعثر (scatter) بين أي عمودين من البيانات نستطيع استخدام الدالة plot العامة الأغراض، فمثلا (plot(wt, mpg والتي يمكن كتابتها أيضا بالصيغة (plot(mpg~wt حيث سيمثل وزن السيارات بقيم wt على محور x فيما المسافة المقطوعة بغالون البنزين الواحد والتي تعطى بقيم mpg ستمثل على المحور y ليظهر لدينا المخطط البياني كما هو موضح في الشكل التالي: في بعض الأحيان قد لا يكون هذا النوع من المخططات البيانية هو الطريقة الأمثل لعرض ما لدينا من معلومات، خصوصا عندما تكون بيانات أحد طرفي العلاقة عبارة عن قيم محددة بعينها وليست قراءات تتوزع على طيف المحور المسندة إليه كما في حالة المخطط البياني الذي تولده التعليمة (plot(cyl, mpg حيث cyl تمثل عدد إسطوانات المحرك، حينها سيكون الشكل الناتج غريبا قليلا وأقل فائدة في التعبير عن ما يربط بين المقادير المرسومة كما هو موضح أدناه: لحسن الحظ فإن سلوك الدالة plot يتعدل بشكل آلي تبعا لطبيعة ونوع البيانات التي تمرر إليها، وما سنقوم به الآن هو تحويل نوع cyl إلى معاملة وذلك باستخدام الأمر (cyl <- factor(cyl، بمعنى أن لهذا المقدار قيم محددة لايستطيع أن يأخذ غيرها، وسنلاحظ طبيعة هذا التغير في طريقة تعامل توابع لغة R المختلفة مع هذا المقدار الجديد بعد تغيير توصيفه (يمكن لك أن تجرب معه الدالة summary لترى أن ماتحصل عليه من ناتج يختلف عما سبق وأن رأيت، فعوضا عن القيمة الصغرى والعظمى والمتوسط والوسيط الخ... وهي المقادير التي توصف بها عادة أي مجموعة قيم عددية، أصبحنا نرى الآن عدد القيم المحددة التي يمتلكها هذا المعامل مقدار تكرار ظهور كل من تلك القيم). ليس هذا فحسب بل إن سلوك الدالة plot سوف يتغير كذلك، فإن حاولت الآن إعادة تنفيذ ذات الأمر السابق (plot(cyl, mpg فسوف تحصل على المخطط البياني التالي: وما يظهر لنا في هذا الشكل هو مجموعة من المخططات الصندوقية لكل قيمة أو مستوى من عدد إسطوانات المحرك في cyl (سنأتي بعد قليل على شرح هذا النوع من المخططات الصندوقية بشيء من التفصيل، فقليلا من الصبر إن كنت غير عارف بها). هناك مخطط بياني آخر ذي طبيعة استخدام إحصائية موجود في جعبتنا ألا وهو المدرج التكراري (Histogram)، وهو يبين طبيعة توزع ما لدينا من قيم على المجال المحصور ما بين الحد الأدنى والأقصى، ففي بعض الأحيان لا يكون تلخيص البيانات بمساعدة الحد الأدنى والأقصى والمتوسط كافيا، حينها نلجأ إلى هذا المخطط البياني والذي يقسم فيه المجال الكلي ما بين الحد الأدنى والحد الأقصى إلى فئات أو مجموعات، ومن ثم نرسم أعمدة بيانية توضح عدد مرات تكرار ظهور القيم ضمن كل واحدة من هذه الفئات أو المجموعات. فعلى سبيل المثال تستطيع تجربة الأمر التالي ("hist(qsec, col="gray لتوضيح توزع معدل التسارع بين السيارات المدروسة حيث تشير القيم في qsec إلى الزمن اللازم لقطع مسافة ربع ميل مقاسا بالثواني، لاحظ أننا اخترنا اللون الرمادي الذي سترسم به الأعمدة وذلك من خلال تحديد قيمة الوسيط col. لدينا نوع آخر من المخططات البيانية ذات الصبغة الإحصائية متاح لنا وهو المخطط الصندوقي آنف الذكر، ويمكن طلب عرض بياناتنا من خلاله باستخدام الدالة ("boxplot(qsec, col="gray حيث سنحصل بالنتيجة على الشكل التالي: حيث يوضح الخطين الأفقيين على طرفي الرسم في الأعلى والأسفل كل من القيمة الصغرى (في الأسفل) والعظمى (في الأعلى)، أما الصندوق الموجود بينهما فتوضح بدايته من الأسفل ما ندعوه بحد الربع الأول (وهو ما كان يظهر ضمن خرج الدالة summary تحت التسمية Q1)، وبالتالي يكون المجال المحدد ما بين القيمة الصغرى وطرف هذا الصندوق يتضمن ربع ما لدينا من قيم، أما المجال المحدد ما بين طرفي الصندوق الأسفل والأعلى فيتضمن بالضبط نصف ما لدينا من قيم حيث أن الحد الأعلى للصندوق هو الربع الثالث أي Q3، أما الخط الذي يقطع ذلك الصندوق بالعرض فهو الوسيط (وليس المتوسط الحسابي)، وهو يدل على الحد الذي يقسم كتلة البيانات التي لدينا إلى مجموعتين متساويتين في العدد إحداهما تتضمن القيم التي تعلو خط الوسيط والأخرى فيها القيم التي تقع أسفل خط هذا الوسيط. في بعض الأحيان قد نرى دوائر أو نقاط تتجاوز حد القيمة العظمى أو تقل عن حد القيمة الصغرى، وهي في واقع الأمر من بياناتنا أيضا لكنها تعامل معاملة القيم الشاذة أو الغريبة وذلك حينما يتجاوز بعدها عن المتوسط ضعفي الإنحراف المعياري (standard deviation) لمجموعة البيانات التي لدينا. إن حجر الزاوية في تصميم أي تجربة علمية على أساس إحصائي سليم يبدأ من توليد التوزيع العشوائي لمعاملاتها حتى لايكون هناك أي تفضيل أو إنحياز لأي منها، كذلك علينا تكرار كل واحدة من تلك المعاملات لأكثر من مرة حتى تكون الاستجابة المدروسة ليست مجرد مصادفة بل تمت المصادقة عليها من خلال إعادتها وتكرارها، إن مجموعة الأوامر التالية تعطي مثالا على طريقة تصميم تجربة بمعاملة لها 12 قيمة مختلفة في 3 مكررات (وهو ما يطلق عليه عادة في التجارب العلمية بتصميم القطاعات العشوائية الكاملة RCBD أي Randomised Complete Block Design): x <- 1:12; RCBD <- replicate(3, sample(x));حيث يشير التركيب 1:12 إلى تسلسل الأرقام من 1 وحتى 12 على التوالي، فيما تقوم الدالة sample ببعثرة عناصر الشعاع x بشكل عشوائي، في حين أن دور الدالة replicate في هذا التركيب هو تكرار ناتج تنفيذ الدالة sample لثلاث مرات، لعرض محتويات التصميم الناتج أكتب RCBD ضمن سطر الأوامر في لغة R ومن ثم إنقر على زر الإدخال (إنتبه إلى أن الأسماء في لغة R حساسة لحالة الأحرف). تجدر الإشارة إلى أنه بإمكانك حفظ مجموعة التعليمات التي تود تنفيذها ضمن ملف نصي، وعادة ما تستخدم اللاحقة R لمثل تلك الملفات (على سبيل المثال script.R)، ومن ثم تستطيع استدعاء ذلك الملف ليتم تنفيذ محتواه من تعليمات وأوامر دفعة واحدة وذلك باستخدام التعليمة ("source("script.R أو حتى من خلال الخيار Source R code في قائمة File. هذه هي نهاية الجزء الثاني من سلسلة المقالات التي تتحدث عن لغة R، في الجزء الثالث سنتناول موضوع الاختبارات الإحصائية. لائحة المراجع: http://www.r-project.orghttp://www.statmethods.nethttp://www.r-tutor.com
  10. تعد لغة R من اللغات التي صعد نجمها حديثا وبشكل سريع بمجال البرمجة العلمية في قطاعي الإحصاء والمعلوماتية الحيوية (bioinformatics) حيث باتت معتمدة على نطاق واسع في كثير من الجامعات ومراكز البحث العلمية، وأصبحنا نرى استخدامها والإشارة إليها في المقالات المنشورة بالمجلات العلمية المحكّمة يزداد بشكل طردي ومتسارع، هذا عدى عن حقيقة كونها لغة حرة مفتوحة المصدر يخضع توزيعها لترخيص GPL الشهير. كل ذلك أدى إلى تزايد ما هو متوفر ومتاح على الشابكة (الإنترنت) من مصادر لها على توزع طيف تلك المصادر، فهناك الكتب الإلكترونية والدروس التعليمية وحتى المناهج الأكاديمية والدورات التدريبية إضافة إلى البرامج الجاهزة والمكتوبة بلغة R لتنفيذ هذه المهمة أو تلك، حتى أنها باتت تحظى ببعض الامتياز مقارنة بالعديد من العمالقة في قطاع البرمجة الرياضياتية العلمية والإحصائية مثل SAS و SPSS خصوصا في مجال توافر الجديد من الطرق والخوارزميات الحديثة، حيث يقاد هذا التوجه في معظمه من طرف الجامعات ممثلة بطلاب الدراسات العليا يحفّزهم على ذلك سهولة بناء الإضافات لهذه اللغة، ويعتبر هذا الأسلوب رغم ما قد يشوبه من نقاط ضعف تتعلق بموثوقية وجودة وغزارة تلك الإضافات الجديدة، والتي تتبع خبرة ومهارة مطوريها وناشريها، لكنها تبقى في القطاع العلمي والأكاديمي أفضل كثيرا من البدائل التجارية التي يعيبها ارتفاع ثمنها من جهة، ومن جهة أخرى بطئ إضافة التحديثات التي تعكس تطور القطاعات العلمية المختلفة، حيث أنها عادة ما تتبع دورة تجارية تتحكم بها الشركات المنتجة. سنحاول في هذه المقالة أن نقدم مدخلا مبسطا ومختصرا لأساسيات هذه اللغة ونستكشف بعضا من إمكانياتها واستخداماتها، والتي أتمنى أن أراها تدرّس في جامعاتنا يوما ما، بحيث تستخدم كأداة للاختبار والتجربة والتطوير ضمن الجلسات العملية لبعض المقررات العلمية في الكليات ذات الاختصاص. هذا هو الجزء الأول في سلسة مؤلفة من أربع مقالات تهدف إلى التعريف بلغة R حيث سيتناول الجزء الثاني منها موضوع المخططات البيانية الإحصائية، أما الجزء الثالث فسيتحدث عن كيفية إجراء بعض الاختبارات الإحصائية بلغة R، فيما نختم السلسلة بجزء رابع يتحدث عن بعض التقنيات المتقدمة في هذه اللغة. يمكنك تحميل لغة R من الموقع الرسمي لها على الشابكة والموجود على العنوان http://www.r-project.org حيث توجد إصدارات منها لمعظم أنظمة التشغيل الشائعة ومنها Windows و Linux وحتى Apple. إن عملية التنصيب سهلة وتخلو من التعقيدات، وعند الانتهاء منها يمكنك تشغيل بيئة عمل لغة R بالنقر على الأيقونة الخاصة بالبرنامج سواء تلك الموجودة على سطح المكتب أو من خلال قائمة البرامج، وحينها ستظهر لك شاشة سطر الأوامر الخاصة بلغة R وهو المكان المعتاد لكتابة الأوامر الخاصة بهذه اللغة كما هو ملاحظ في الشكل التالي: وبما أننا ذكرنا أن هذه اللغة واسعة الانتشار في مجال النشر العلمي، لذا دعونا نطلع على تعليمتنا الأولى وهي تعليمة ()citation والتي تعرض الطريقة الرسمية للإشارة إلى لغة R كمرجع ضمن لائحة المراجع المستخدمة في أي ورقة علمية كما هو موضح بالشكل التالي: في لغة R تستخدم الفاصلة المنقوطة للفصل فيما بين كل أمر من أوامر اللغة الموجودة على سطر واحد (فيما لاحاجة لتلك الفواصل المنقوطة إن كانت كل تعليمة ترد ضمن سطر مستقل بها)، كما ترى فإن خرج تنفيذ أي أمر أو دالة بلغة R يظهر بعدها مباشرة، وهكذا تتكون جلسة العمل الاعتيادية من تنفيذ لتتالي من الأوامر والتعليمات وصولا إلى إنجاز العمل أو التحليل المطلوب، ويمكنك باستخدام أزرار الأسهم إلى الأعلى وإلى الأسفل من التنقل عبر مجموعة الأوامر التي تم تنفيذها خلال جلسة العمل الحالية جيئة وذهابا، كذلك يمكنك استعراض آخر 15 أمر على سبيل المثال من خلال الدالة (history(15، هذا عدى عن إمكانية حفظ وتخزين أرشيف أوامر الجلسة الحالية في ملف باستخدام الدالة ("savehistory("myfile ومن ثم استعادة ذلك الأرشيف في جلسة عمل جديدة منفصلة باستخدام الدالة "("loadhistory("myfile، هناك اختصار آخر مفيد حينما ترى أن نافذة سطر الأوامر لديك أصبحت مزدحمة بالنتائج وتريد تنظيفها، فكل ما عليك القيام به هو النقر على الاختصار Ctrl+L (مع ملاحظة أن ذلك لن يحذف أي من البيانات التي تم تحميلها إلى البرنامج والمحفوظة بالتالي في الذاكرة، بل يقوم فقط بتنظيف الشاشة المعروضة أمامك). قبل الانطلاق قدما في استعراض ما في هذه اللغة من دوال وكيفية استخدام كل منها، دعونا بداية نتعرف على طريقة الحصول على المساعدة فيها، إذ يتدرج الأمر من طلب الحصول على المساعدة الخاصة بأمر محدد أو دالة بعينها، وذلك بذكر اسم الأمر أو الدالة عقب علامة الاستفهام ومن ثم النقر على زر الإدخال، فمثلا يقوم الأمر read.table? بعرض الصفحة الخاصة بتوثيق التعليمة read.table ضمن ملفات المساعدة الخاصة بلغة R. أما إن أردت البحث عن مفهوم معين أو كلمة مفتاحية ما دون أن تعلم تماما أي الدوال هي التي تتعامل معها في لغة R، فيمكنك استخدام الأمر ("help.search("data input لتعرض عليك بعدها مجموعة من الأوامر ذات الصلة بهذا المفهوم، وتستطيع حينها الحصول على شرح أو مساعدة تفصيلية لأي من تلك الدوال بالطريقة التي أشرنا إليها سابقا. هناك وسيلة مساعدة أخرى متوفرة في لغة R موجهة إلى فئة المبرمجين الذين يفضلون رؤية الأمثلة وهي تعمل على أن يقرؤوا العشرات من أسطر ملفات المساعدة، وهؤلاء يمكنهم استخدام الأمر example بعد أن تمرر له اسم الدالة المراد الحصول على أمثلة عملية عن طريق استخدامها، فعلى سبيل المثال يمكنك تجربة الأمر (example(mean. وطالما أننا نتحدث عن وسائل وأساليب الحصول على المساعدة، أجد أنه من المفيد ذكر طريقة إضافة التعليقات في لغة R، وهو أسلوب لا تخفى ضرورته على أي مبرمج محترف، ففي لغة R التعليقات هي كل نص يتلو الرمز # سواء ظهر من بداية السطر أو جاء بعد تعليمة ما، لكن الغريب أن لغة R تفتقر إلى طريقة لجعل مقطع كامل يعامل معاملة التعليقات (كما هو حال استخدام أسلوب التأطير /* ... */ في العديد من لغات البرمجة الأخرى). الخطوة التالية التي يجب تعلمها الآن هي آلية استيراد البيانات وقراءتها من مصادرها وإن تعددت تنسيقات وصيغ تلك المصادر، فعلى سبيل المثال يمكنك القراءة من جداول البيانات المحفوظة بتنسيق csv باستخدام الأمر التالي: data <- read.csv("d:/mydir/myfile.csv", header=TRUE, sep=”;”)كما هو واضح فقد أشرنا إلى أن السطر الأول من محتويات الملف المستورد هو عبارة عن تسميات الأعمدة من خلال الخاصية header=TRUE، كذلك تم تحديد الفاصل ما بين عمود وآخر من البيانات على أنه الفاصلة المنقوطة من خلال الخاصية ";"=sep. وقد استخدمنا في هذا المثال الاسم الكامل للملف بما فيه المسار، أما إن ذكرت اسم الملف دون تحديد المسار فسيتم البحث عنه ضمن ما يدعى بمجلد العمل، ولمعرفة أين يشير مجلد العمل الحالي لديك يمكنك استخدام الأمر ()getwd، أو يمكنك تحديد مجلد عمل مختلف باستخدام الأمر ("setwd("d:/mydir ، من جهة أخرى يمكنك الاستعاضة عن كل ذلك باستخدام الأمر ()file.choose عوضا عن ذكر اسم الملف ومساره، حيث ستحصل عند التنفيذ على صندوق حوار يتيح للمستخدم استعراض ما على حاسوبه من مجلدات وملفات وصولا إلى اختيار الملف المطلوب. كما سبق وأن رأينا فإن عملية الإسناد في لغة R يشار إليها بالرمز <- وهي الطريقة الأكثر شيوعا مقارنة برمز المساواة = والذي يصح استخدامه على الرغم من عدم شيوعه بين معشر المبرمجين بلغة R، إن البيانات المقروءة سيتم حفظها ضمن إطار بيانات (dataframe) أسميناه في حالة مثالنا السابق data، ويمكنك استعراض محتويات إطار البيانات ذلك بمجرد كتابة اسمه ومن ثم النقر على زر الإدخال ضمن سطر الأوامر، أما إن كانت كمية البيانات ضخمة فمن المفيد استخدام أي من الأمرين (head(data والذي يعرض مجموعة من الأسطر مقتطعة من بداية كتلة البيانات، أو الأمر (tail(data والذي يعرض مجموعة أخرى من الأسطر مقتطعة من نهاية كتلة البيانات ذاتها. كذلك تستطيع استخدام الأمر التالي: data <- edit(data)لعرض تلك البيانات ضمن نافذة جدول بسيط يتيح للمستخدم تنقيحها ومن ثم إعادتها إلى ذات إطار البيانات الأصلي كما هو موضح من الأمر السابق. إن كانت البيانات مخزنة في ملف نصي يستخدم رمز الجدولة للفصل ما بين أعمدته (أي text tab delimated)، فعليك حينها استخدام الأمر read.data عوضا عن الأمر read.csv الموضح في المثال السابق، وهناك حالة خاصة عندما تكون البيانات المراد استيرادها موجودة فعليا ضمن الحافظة، وحينها عليك الاستعاضة عن ذكر اسم الملف بالعبارة “clipboard”. لدى لغة R أيضا المزيد من تعليمات الاستيراد التي تختص كل منها بتنسيق مختلف، فعلى سبيل المثال لا الحصر نذكر الأوامر التالية: read.spss و read.systat و read.mtp و read.xport. نستطيع الوصول بكل سهولة إلى أي جزئية في إطار البيانات الحالي من خلال المرونة التي تتيحها لنا لغة R، فلو كان لدينا إطار عمل يدعى data على سبيل المثال، فإن التعبير [data[i,j سيشير إلى العنصر أو القيمة الموجودة في السطر i والعمود j، أما التعبير [,data[i فيشير إلى كامل السطر i في حين أن التعبير [data[,n:m فيشير بدوره إلى مجموعة الأعمدة بدءا من n حتى m، من جهة أخرى فإن التعبير [,data[-i فيشير إلى كامل البيانات ضمن data فيما عدى السطر i، وأخيرا فإن التعبير [,(data[c(n,m فهو يشير إلى السطرين n و m تحديدا دون غيرهما من أسطر البيانات في data. تأتي لغة R محزومة مع إطار بيانات افتراضي يدعى mtcars يتضمن بيانات مأخوذة من مجلة Motor Trend لعام 1974 تقارن فيها عشر من مواصفات التصميم والأداء لأكثر من ثلاثين سيارة منتجة في العام 1973، وسنستخدم من بيانات تلك المواصفات في مقالتنا هذه كل من mpg ويقصد بها عدد الأميال المقطوعة بغالون البنزين الواحد، و cyl الذي يمثل عدد الإسطوانات في محرك السيارة، و wt وهو الوزن بآلاف الليبرات (الليبرة تقريبا نصف كيلوغرام)، وكذلك qsec وهو التسارع مقاسا بالزمن اللازم لقطع مسافة ربع ميل (لمزيد من المعلومات والتفاصيل يمكنك طلب المساعدة باستخدام التعليمة ?mtcars). سنستخدم هذه البيانات في استعراض مجموعة من الأمثلة حول ما سيتلو ذكره من دوال وتقنيات إحصائية. بمجرد استيراد بياناتك يمكنك الوصول إلى القيم الموجودة في أي من أعمدة جدولك باستخدام الصيغة mtcars$mpg على سبيل المثال حيث mpg يشير إلى اسم العمود، أما إن أردت أسلوبا أكثر سهولة واختصارا يقتصر على ذكر اسم العمود فقط دون الحاجة إلى ذكر اسم إطار البيانات المأخوذ منه في كل مرة، فعليك بداية استخدام الأمر (attach(mtcars عقب استيرادك للبيانات، وحينها يكفي ذكر الاسم mpg للدلالة على ذات العمود من البيانات. وتستطيع استعراض ما تحويه ذاكرة الجلسة الحالية من بيانات في لغة R باستخدام الأمر ()ls ، إضافة إلى ذلك يمكنك حذف أي من كتل البيانات تلك من ذاكرة الجلسة الحالية باستخدام الأمر (rm(x حيث يشير الرمز x إلى اسم كتلة البيانات سواء كانت عمود (أي شعاع من القيم) أو مصفوفة أو إطار بيانات كامل، حتى أنك تستطيع حذف كل ما يوجد الآن في ذاكرة الجلسة الحالية من بيانات سبق وأن تم تحميلها وذلك باستخدام الأمر (()rm(list=ls. عند قيامك بتحميل بياناتك إلى ذاكرة الجلسة الحالية، تصبح مستعدا للبدء في العمل عليها لتطبيق تحليلاتك المختلفة. ومن الأوامر الأساسية المتاحة نذكر على سبيل المثال الدالة (max(mpg والتي تعيد القيمة العظمى ضمن العمود mpg (أي شعاع القيم mpg)، أما الدالة (min(mpg فهي على عكس سابقتها تعيد القيمة الصغرى، في حين أن الدالة (mean(mpg تعيد المتوسط الحسابي للقيم الواردة في mpg، والدالة (median(mpg تعيد قيمة الوسيط (الوسيط هو القيمة التي تقع في المنتصف عند ترتيب قيم mpg تصاعديا، وبالتالي تكون نصف قيم mpg تزيد عن قيمة هذا الوسيط فيما النصف الآخر يقل عنها، وعادة ما يستخدم الوسيط للدلالة على مركز المجموعة حينما تكون هناك قيم متطرفة زيادة أو نقصانا بحيث تؤثر على المتوسط الحسابي وتؤدي إلى انحيازه). من جهة أخرى هناك دوال تستخدم لوصف مدى تشتت قراءات وقيم mpg حول النقطة المركزية الممثلة بالمتوسط، ومنها الدالة (var(mpg والتي تحسب مقدار التباين، والدالة (sd(mpg والتي تعيد قيمة الانحراف المعياري. يحسب التباين من خلال العلاقة التالية أي أننا نراكم مجموع فروقات كل واحدة من قراءاتنا عن قيمة المتوسط بعد أن نربّع هذا الفرق، حيث تخدم عملية التربيع في جعل الناتج موجبا دوما (كون الأخطاء أو الفروقات موجودة سواء كانت بالزيادة أو النقصان، وإن لم نفعل ذلك لحصلنا دوما على الناتج 0 كمحصلة لعملية الجمع تلك)، الخدمة الثانية التي نحصل عليها من هذا التربيع هي تقليل أثر الفروقات الصغيرة على حساب تعظيم ومضاعفة تأثير الفروقات الكبيرة (فتربيع الأرقام الصغيرة لايضاعفها بقدر ما يفعل مع الأرقام الكبيرة، ولولا ذلك لاكتفينا بالقيمة المطلقة للفروقات المحسوبة عن المتوسط عند حساب مقدار التباين). من جهة ثانية فإن الانحراف المعياري يقوم بتقييس معيار التباين وذلك للتعبير عن التشتت بصيغة مستقلة عن عدد العينات أو القراءات التي لدينا (والتي تؤثر على قيمة التباين كونه حساب تراكمي يزداد بازدياد عدد القراءات)، وتتم عملية التقييس تلك من خلال تقسيم مقدار التباين الناتج على (n-1) وهو عدد العينات منقوصا منه واحد، وبعد عملية القسمة تلك نحسب الجذر التربيعي الناتج وذلك حتى يعود المقدار المحسوب إلى ذات فضاء القيم الموجودة لدينا بدلا من كونه في حالة التباين من مرتبة مربّع تلك الأرقام، فيعود من السهل علينا مقارنته مباشرة مع قيمنا أو المتوسط الخاص بتلك القيم. أما الدالة (summary(mpg فهي عامة الاستخدام ويختلف سلوكها وخرجها بحسب الكائن الممرر إليها، ففي حالة تمرير شعاع من القيم العددية فسيكون ناتج تنفيذها هو ملخص لتلك القيم والذي يشمل كل من المتوسط والوسيط إضافة إلى القيمتين العظمى والصغرى والربعين الأول والثالث (ويعرفان بشكل مشابه للوسيط، إذ يشير الربع الأول إلى القيمة التي تقل عنها ربع قراءاتك بعد ترتيبها تصاعديا، فيما الربع الثالث كما هو واضح من اسمه فهو القيمة التي تقل عنها ثلاثة أرباع قيم mpg المرتبة تصاعديا، وهما قيمتان تساعدان في فهم كيفية توزع بياناتك). كذلك تمتلك لغة R مجموعة واسعة من الدوال الرياضياتية مثل (abs(x والتي تعيد القيمة المطلقة (الإيجابية الإشارة دوما) للقيمة أو شعاع القيم المدخل لها، والدالة (sqrt(x التي تحسب الجذر التربيعي والتي نستطيع الحصول على نفس وظيفتها من خلال عملية الرفع إلى أس مقداره نصف أي x^0.5 ، كذلك لدينا الدوال المثلثية المختلفة مثل (sin(x و (cos(x وغيرهما، هذا بالإضافة إلى طيف من دوال التقريب المختلفة مثل (floor(2.718 والتي ستعيد القيمة 2 كأكبر عدد صحيح أصغر من القيمة المعطاة، وكذلك الدالة (ceiling(3.142 والتي ستعيد القيمة 4 كأصغر عدد صحيح أكبر من القيمة المعطاة، أما الدالة (round(2.718, digits=2 فستعيد القيمة 2.72 حيث تقوم هذه الدالة بعملية التقريب الحسابية المعتادة مع إمكانية تحديد عدد الخانات العشرية بعد الفاصلة والتي تريد الاحتفاظ بها. لدينا أيضا دوال التحويل مثل (log(x التي تحسب اللوغاريتم الطبيعي للمقدار x، فيما تحسب الدالة (log10(x اللوغاريتم العشري لذات المقدار x، مع هذا يمكنك استخدام الصيغة الأكثر مرونة وهي (log(x,n والتي تحسب اللوغاريتم لأي أساس يحدده المبرمج من خلال المقدار n، فمثلا يمكنك حساب اللوغاريتم الثنائي للمقدار x باستخدام التعليمة (log(x,2. هذه هي نهاية الجزء الأول من سلسلة المقالات التي تتحدث عن لغة R، سنتحدث في الجزء الثاني عن المخططات البيانية الإحصائية. لائحة المراجع: http://www.r-project.orghttp://www.statmethods.nethttp://www.r-tutor.com
×
×
  • أضف...