الإحصاء وتحليل البياناتبرمجة R

كيفية استخدام دالة runif في لغة R (4 أمثلة)

دليل أكاديمي شامل يشرح كيفية استخدام دالة runif في لغة R لتوليد أرقام عشوائية من التوزيع المنتظم مع 4 أمثلة تطبيقية مفصلة.

تاريخ النشر

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

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

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

1. مقدمة إلى توليد الأرقام العشوائية ودالة runif في لغة R

1.1 مفهوم التوليد شبه العشوائي للأرقام (Pseudo-Random Number Generation)

يقوم التوليد الحسابي للأرقام داخل أجهزة الحاسوب الرقمية على خوارزميات قطعية (Deterministic Algorithms) تُعرف باسم مولدات الأرقام شبه العشوائية (Pseudo-Random Number Generators – PRNGs). وعلى النقيض من العشوائية الفيزيائية الحقيقية المستمدة من ظواهر طبيعية غير متوقعة، مثل الضوضاء الحرارية أو التحلل الإشعاعي، فإن المتتاليات شبه العشوائية هي متواليات حسابية محتومة تُنتج بواسطة صيغ رياضية دقيقة تبدأ بنقطة انطلاق تسمى “البذرة” (Seed). ومع ذلك، تتميز هذه المتتاليات بخصائص إحصائية تجعلها غير قابلة للتمييز عملياً عن السلاسل العشوائية الحقيقية عند إخضاعها لاختبارات الاستقلالية والتوزيع المنتظم.

تعتمد نواة لغة R بشكل افتراضي على خوارزمية Mersenne-Twister التي طورها العالمان ماكوتو ماتسوموتو وتاكوجي نيشيمورا عام 1998 (وتحديداً النسخة MT19937). وتوفر هذه الخوارزمية دورة تكرار أسطورية الطول تصل إلى (2^19937 – 1)، مما يعني أن المتتالية لا تكرر نفسها أبداً ضمن أي تجربة محاكاة واقعية، إلى جانب تمتعها بتوزيع متوازن متساوٍ في فضاءات متعددة الأبعاد تصل إلى 623 بعداً. هذا الأساس الخوارزمي الرصين يمنح الباحثين والمهندسين ثقة مطلقة في جودة الأرقام المولدة وخلوها من الأنماط الدورية الخفية أو الارتباطات الذاتية المشوهة للنماذج الإحصائية.

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

1.2 التعريف الوظيفي لدالة runif وأهميتها البرمجية

تُشتق تسمية الدالة runif في بيئة R كاختصار تركيبي يجمع بين الحرف r الذي يشير إلى التوليد العشوائي (Random Generation) واللاحقة unif الدالة على التوزيع المنتظم (Uniform Distribution). وتتمثل الوظيفة المحورية لهذه الدالة في اشتقاق متجهات عددية حقيقية تتوزع قيمها توزيعاً منتظماً ومستمراً عبر مجال عددي محدد، حيث يتمتع كل مجال فرعي داخل هذا النطاق بفرصة متكافئة تماماً لظهور القيم ضمنه.

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

تتكامل دالة runif بنيوياً ضمن عائلة التوزيعات الاحتمالية القياسية المدمجة في نواة R، والتي تتبع نمط تسمية موحد وقياسي يشمل: دوال التوليد العشوائي المسبوقة بحرف (r) مثل rnorm للتوزيع الطبيعي وrbinom للتوزيع ذي الحدين وrpois لتوزيع بواسون، ودوال الكثافة الاحتمالية المسبوقة بحرف (d) مثل dunif، ودوال التوزيع التراكمي المسبوقة بحرف (p) مثل punif، ودوال نقاط التوزيع أو المئينات المسبوقة بحرف (q) مثل qunif. هذا الاتساق المعماري يجعل استيعاب runif مدخلاً شاملاً لفهم منظومة الاحتمالات في لغة R بالكامل.

1.3 الاستخدامات المنهجية في البحوث العلمية والتحليل الإحصائي

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

وفي مجال النمذجة الإحصائية المتقدمة والتعلم الآلي، تُعد الدالة أداة أساسية في تنفيذ تقنيات إعادة أخذ العينات (Resampling Techniques) مثل تقنية بوتستراب (Bootstrapping) وطرق التحقق المتبادل (Cross-Validation). حيث يُستخدم التوزيع المنتظم لاختيار نقاط البيانات أو تقسيم مجموعات التدريب والاختبار بطريقة عشوائية منتظمة تمنع التداخل وتحافظ على التمثيل المتوازن للبنى الإحصائية داخل البيانات الأصلية.

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

2. الأساس الرياضي والإحصائي للتوزيع المنتظم المستمر (Uniform Distribution)

2.1 دالة الكثافة الاحتمالية (Probability Density Function)

يُعرف التوزيع المنتظم المستمر على الفترة المغلقة أو المفتوحة من [a, b] (والتي يرمز لها في لغة R بالمعاملين min وmax) بأنه التوزيع الاحتمالي الذي تكون فيه الكثافة الاحتمالية ثابتة تماماً وغير متغيرة على امتداد كامل النطاق، ومساوية للصفر في أي نقطة خارجه. وتُصاغ دالة الكثافة الاحتمالية الرياضية f(x) بالمعادلة التالية:

f(x) = 1 / (b – a) عندما تكون a ≤ x ≤ b، وتساوي 0 عندما تكون x < a أو x > b.

يعكس هذا الثابت الرياضي حقيقة أن المتغير العشوائي المستمر X يمتلك نفس فرصة الوقوع في أي فترة فرعية متساوية الطول داخل المجال الإجمالي. فإذا كانت الفترة الكلية محددة بين 0 و10، فإن احتمالية وقوع القيمة بين 1 و2 تماثل تماماً احتمالية وقوعها بين 8 و9، حيث تبلغ الكثافة الاحتمالية قيمة ثابتة مقدارها 0.1 عبر كامل النطاق.

تخضع هذه الدالة لشرط التكامل الاحتمالي الأساسي، حيث يجب أن تكون المساحة الكلية الواقعة تحت منحنى دالة الكثافة مساوية للواحد الصحيح (1.0). ويمكن إثبات ذلك رياضياً بحساب التكامل المحدود للدالة f(x) من الحد الأدنى a إلى الحد الأعلى b: تكامل (1 / (b – a)) بالنسبة لـ x يعطي [x / (b – a)] مقيمة بين a وb، وهو ما يساوي (b – a) / (b – a) = 1. هذا التكامل يضمن بقاء النموذج متوافقاً تماماً مع بديهيات نظرية الاحتمالات الكلاسيكية لكولموغوروف.

2.2 دالة التوزيع التراكمي (Cumulative Distribution Function)

تمثل دالة التوزيع التراكمي، والتي يرمز لها بالرمز F(x)، احتمالية أن يأخذ المتغير العشوائي المستمر X قيمة أقل من أو مساوية لقيمة معينة x، أي P(X ≤ x). وتُشتق هذه الدالة عبر حساب التكامل التراكمي لدالة الكثافة الاحتمالية من الحد الأدنى a حتى النقطة x، وتُعطى بالصيغة الجبرية التالية:

F(x) = 0 لقيم x < a، وF(x) = (x – a) / (b – a) لقيم a ≤ x ≤ b، وF(x) = 1 لقيم x > b.

تتميز دالة التوزيع التراكمي للتوزيع المنتظم بسلوك خطي مستقيم ومتصل ذي ميل ثابت مقداره (1 / (b – a)). ويعبر هذا التغير الخطي المستمر عن التزايد المنتظم للاحتمال التراكمي مع كل وحدة إزاحة موجبة على طول المحور الأفقي. ويتيح هذا الاقتران الخطي حساب احتمالية وقوع المتغير في أي فترة محددة [x1, x2] عبر الطرح المباشر: P(x1 ≤ X ≤ x2) = F(x2) – F(x1) = (x2 – x1) / (b – a).

تحمل دالة التوزيع التراكمي للتوزيع المنتظم أهمية رياضية استثنائية في نظرية الاحتمالات، إذ ترتبط مباشرة بمبرهنة “التحويل الاحتمالي المتكامل” (Probability Integral Transform). تنص هذه المبرهنة على أنه إذا كان X متغيراً عشوائياً مستمراً يمتلك دالة توزيع تراكمي F(X)، فإن المتغير المحول U = F(X) يتبع بالضرورة توزيعاً منتظماً معيارياً U(0, 1). وعلى العكس تماماً، يمكن استخدام مقلوب الدالة التراكمية F^(-1)(U) لتحويل أرقام عشوائية منتظمة إلى أي توزيع احتمالي مرغوب، وهو ما يشكل الأساس النظري لتوليد التوزيعات في الحوسبة الإحصائية.

2.3 العزوم الإحصائية: القيمة المتوقعة والتباين والوسيط

تتحدد الخصائص الهيكلية لأي توزيع احتمالي من خلال عزومه الإحصائية الأساسية. وفي حالة التوزيع المنتظم المستمر على الفترة [a, b]، تُشتق القيمة المتوقعة (Expected Value) أو المتوسط الحسابي النظري E(X) بتكامل حاصل ضرب x في دالة الكثافة الاحتمالية على الفترة، مما يقود مباشرة إلى الصيغة البسيطة التالية:

E(X) = (a + b) / 2

يعكس هذا المتوسط النظري مركز الثقل الهندسي للمستطيل الممثل لدالة الكثافة، ويقع بدقة متناهية في المنتصف الحسابي للحدين الأدنى والأعلى. وبالمثل، يُشتق العزم المركزي الثاني الذي يمثل التباين الرياضي Var(X) من خلال حساب التكامل E[(X – E(X))^2]، ويصل بنا الاستنتاج الرياضي إلى العلاقة التالية:

Var(X) = (b – a)^2 / 12

أما الانحراف المعياري (Standard Deviation)، فيساوي الجذر التربيعي للتباين: SD(X) = (b – a) / sqrt(12). يوضح هذا التباين أن تشتت البيانات يتناسب طردياً مع مربع طول النطاق الكلي، بينما يمثل المقسوم عليه الثابت (12) خاصية هندسية تنبع من تكامل الدالة التربيعية على مجال مستطيل منتظم.

وفيما يتعلق بمقاييس النزعة المركزية الأخرى، فإن التماثل التام لدالة الكثافة الاحتمالية حول نقطة المنتصف يفرض تطابقاً كاملاً بين المتوسط الحسابي وقيمة الوسيط (Median) وقيمة منتصف المدى (Midrange)، حيث تتساوى جميعها عند النقطة (a + b) / 2. ونظراً لعدم وجود قيمة وحيدة أكثر تكراراً من غيرها، فإن التوزيع يُعد توزيعاً عديم المنوال (Non-modal) أو ذا منوال لانهائي يمتد على كامل النطاق. وتوفر هذه الخصائص معايير مرجعية دقيقة نستخدمها لتقييم صحة مخرجات دالة runif عند مقارنة المؤشرات الوصفية للعينات المولدة بالقيم النظرية المتوقعة.

3. بنية دالة runif، وسائطها المدخلة، وقيمها الافتراضية

3.1 الصيغة التركيبية العامة (Syntax Structure)

تتميز دالة runif في لغة R ببنية برمجية مباشرة ورشيقة مصممة لتوفير أقصى درجات المرونة والأداء. وتُعرف الصيغة العامة لاستدعاء الدالة على النحو التالي:

runif(n, min = 0, max = 1)

تقبل الدالة ثلاثة وسائط مدخلة أساسية: المعامل الأول n وهو وسيط إجباري يحدد حجم العينة أو عدد القيم الرقمية المطلوب توليدها، والمعامل الثاني min وهو وسيط اختياري يحدد الحد الأدنى لنطاق التوليد، والمعامل الثالث max وهو وسيط اختياري يحدد الحد الأعلى للنطاق. تُرجع الدالة متجراً عددياً (Numeric Vector) من النمط المضاعف (Double-precision floating-point) يحتوي على القيم المولدة.

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

3.2 الوسيط n ودوره في تحديد حجم العينة المنتجة

يتحكم الوسيط n مباشرة في حجم الذاكرة المخصصة للمتجه الناتج وعدد الدورات الخوارزمية التي سينفذها مولد الأرقام شبه العشوائية في النواة البرمجية. ويجب أن يكون n عدداً صحيحاً موجباً غير سالب. وفي حال تمرير قيمة عشرية للوسيط n (مثل 10.7)، فإن لغة R تقوم باقتطاع الجزء العشري تلقائياً والتعامل معه كعدد صحيح (10) دون إطلاق تحذير، بينما يؤدي تمرير قيمة سالبة إلى توقف التنفيذ فوراً وظهور خطأ صريح (Error: invalid arguments).

يلعب حجم العينة n دوراً حاسماً في تحقيق “قانون الأعداد الكبيرة” (Law of Large Numbers). فعند توليد قيم صغيرة لـ n (مثل n = 5 أو n = 10)، تكون التباينات التجريبية مشتتة وقد تبتعد المقاييس الوصفية للبيانات المولدة عن المقاييس النظرية للتوزيع. بينما عند رفع قيمة n إلى أحجام كبيرة (مثل n = 100,000 أو n = 1,000,000)، تتقارب الإحصاءات التجريبية (المتوسط والانحراف المعياري وشكل المدرج التكراري) تقارباً شبه تام مع المنحنى النظري المنتظم.

من الناحية المعمارية، تُعالج لغة R الوسيط n من خلال حجز مساحة خطية متصلة داخل ذاكرة الوصول العشوائي (RAM) قبل بدء عملية التوليد الحسابي. هذا التخصيص المسبق (Pre-allocation) يمنح الدالة كفاءة وسرعة فائقة عند توليد مصفوفات أو متجهات عملاقة، متفوقة بذلك على لغات البرمجة العامة التي قد تعتمد على التوسيع الديناميكي لمصفوفات البيانات أثناء التنفيذ.

3.3 الوسيطان min وmax والحدود الافتراضية للنطاق الاحتمالي

صُممت دالة runif بقيم افتراضية قياسية تجعل استدعاء الدالة مقتصراً على تمرير الوسيط n فقط عند الرغبة في التوليد المعياري. وتأخذ المعاملات الافتراضية القيم: min = 0 وmax = 1. هذا النطاق المعياري [0, 1] هو الأساس الذي تُبنى عليه كافة التحويلات الاحتمالية والعمليات الرياضية في المحاكاة الإحصائية.

تستوعب الدالة إدخال أي أعداد حقيقية موجبة أو سالبة للحدين min وmax، بما في ذلك الأعداد العشرية الدقيقة والأعداد المتناهية في الصغر أو الكبر. على سبيل المثال، يمكن تحديد النطاق بين -500.5 و+250.75 دون أي قيود. وتعتمد الخوارزمية الداخلية على معادلة قياسية لتحويل القيمة المولدة معيارياً u من المجال [0, 1] إلى المجال المستهدف [min, max] عبر الصيغة الرياضية المباشرة: x = min + u * (max – min).

تفرض الدالة قواعد منطقية صارمة للتحقق من صحة المدخلات. فإذا قام المبرمج بتمرير قيمة min أكبر من قيمة max (مثل: min = 100, max = 50)، فإن R تتعامل مع هذا الإدخال بإطلاق خطأ صريح أو إرجاع قيم غير معرفة (NaN) مصحوبة بتحذير برمجي يفيد بعدم منطقية النطاق، نظراً لأن طول الفترة (max – min) يصبح قيمة سالبة، وهو ما يهدم الأسس الرياضية لدالة الكثافة الاحتمالية الموجبة دائماً.

4. أهمية قابلية التكرار وضبط البذور العشوائية باستخدام set.seed()

4.1 الآلية البرمجية لعمل دالة set.seed()

تعتمد خوارزميات التوليد شبه العشوائي (PRNGs) على معادلات تكرارية رياضية تأخذ قيمة مدخلة سابقة لإنتاج القيمة العشوائية التالية. وتُسمى الحالة الابتدائية التي تبدأ منها هذه السلسلة الحسابية باسم “البذرة العشوائية” (Random Seed). تتيح دالة set.seed() في لغة R للمبرمج تحديد وضبط هذه النقطة الابتدائية بدقة من خلال تمرير عدد صحيح يمثل المعرف الرقمي للبذرة.

عند تنفيذ الأمر set.seed(123) على سبيل المثال، يتم تهيئة السجلات الداخلية لمولد Mersenne-Twister وضبط مصفوفتها الحسابية في حالة ابتدائية محددة وثابتة. وبمجرد استدعاء دالة runif بعدها مباشرة، ستتحرك الخوارزمية عبر نفس المسار الرياضي الدقيق لتنتج متتالية رقمية متطابقة بنسبة 100% في كل مرة يُعاد فيها تنفيذ هذا الكود البرمجي، سواء تم التشغيل على نفس الجهاز أو على حاسوب فائق الأداء في طرف آخر من العالم.

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

4.2 أهمية تكرارية النتائج في البحث العلمي والتحليل الإحصائي

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

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

كذلك تضمن البذور العشوائية التوافق والمزامنة الفعالة بين أعضاء الفرق البحثية ومطوري البيانات المشتركة. فعند مشاركة مستودعات الشيفرات عبر منصات مثل GitHub أو نشر تقارير ديناميكية عبر R Markdown وQuarto، يضمن تضمين دالة set.seed() ثبات الجداول والرسوم البيانية والتقديرات الإحصائية عبر جميع النسخ والوثائق المنشورة، مما يمنع التضارب في التحليلات التفسيرية.

4.3 التطبيق العملي للبذور العشوائية قبل استدعاء runif

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

تتطلب إدارة البذور العشوائية في مشاريع المعالجة المتوازية الضخمة (Parallel Computing) استراتيجيات متقدمة. فعند توزيع العمليات الحسابية على عدة نوى معالجة (Multi-core Processing) باستخدام حزم مثل parallel أو future، لا يكفي استخدام set.seed() الكلاسيكية، لأن ذلك قد يؤدي إلى توليد نفس السلاسل العشوائية عبر جميع النوى وتكرار النتائج بشكل خاطئ. في هذه الحالات، يُعتمد على مولدات بذور متوازية مستقلة، مثل مولد L’Ecuyer-CMRG (عبر الأمر RNGkind(“L’Ecuyer-CMRG”))، لضمان استقلالية السلاسل المولدة في كل مسار معالجة.

يوضح التحليل الحسابي التالي السلوك التنفيذي الدقيق للبذور:

  • الخطوة 1: استدعاء set.seed(42) يليه استدعاء runif(3) سينتج دائماً نفس الثلاثة أرقام المحددة.
  • الخطوة 2: استدعاء runif(3) للمرة الثانية على التوالي سينتج ثلاثة أرقام جديدة تماماً ومستمرة في السلسلة.
  • الخطوة 3: إعادة استدعاء set.seed(42) يليه runif(3) سيعيد إنتاج نفس الأرقام الثلاثة التي ظهرت في الخطوة 1 بدقة تامة.

5. المثال 1: توليد قيم عشوائية بنطاق مخصص (Basic Random Values)

5.1 سيناريو التجربة وإعداد البيئة البرمجية

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

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

نقوم أولاً بضبط البذرة عبر الأمر: set.seed(5)

ثم نقوم بتوليد المتجه وحفظه في متغير مخصص عبر الأمر: random_values <- runif(n = 10, min = 50, max = 100)

وأخيراً نقوم بطباعة المتجه في نافذة الأوامر عبر استدعاء: random_values

5.2 التحليل المعمق للمخرجات الحسابية

عند تنفيذ هذه الأوامر بالترتيب الدقيق الموضح، تُرجع لغة R متجراً عددياً مستمراً يحتوي على 10 قيم حقيقية ذات دقة فاصلة عائمة مزدوجة. وتظهر المخرجات الحسابية الدقيقة على النحو التالي:

القيمة الأولى: 60.01072 | القيمة الثانية: 84.26084 | القيمة الثالثة: 95.84277 | القيمة الرابعة: 64.21852 | القيمة الخامسة: 55.23237 | القيمة السادسة: 85.05141 | القيمة السابعة: 76.39800 | القيمة الثامena: 90.39655 | القيمة التاسعة: 97.82500 | القيمة العاشرة: 55.52265.

يكشف الفحص الرياضي المتأني لهذه المخرجات عن عدة حقائق جوهرية تؤكد دقة عمل خوارزمية التوليد:

  • التحقق من الحدود: جميع القيم المولدة تقع بدقة متناهية داخل الفترة المغلقة [50, 100]، حيث نلاحظ أن أدنى قيمة هي 55.23237 (أكبر من 50) وأعلى قيمة هي 97.82500 (أقل من 100)، مما يثبت الامتثال الصارم لحدود النطاق البرمجي.
  • الطبيعة المستمرة للكسور: تحتوي القيم على سلاسل ممتدة من الكسور العشرية، مما يوضح أن التوزيع مستمر (Continuous) وليس متقطعاً (Discrete)، وهو ما يحافظ على التمايز العددي بين القياسات.
  • التشتت العشوائي المتكافئ: بالرغم من أن دالة الكثافة الاحتمالية مسطحة تماماً ومتساوية عبر المجال (بقيمة ثابتة = 1/50 = 0.02)، إلا أن القيم الناتجة لا تظهر تباعداً هندسياً متساوياً بل تتشتت عشوائياً، وهو السلوك الإحصائي الصحيح للعينات العشوائية الصغيرة التي تبدي تبايناً موضعياً قبل أن تتقارب إحصائياً مع زيادة الحجم n.

5.3 التطبيقات الميدانية للمثال الأول

يمثل توليد المتغيرات المستمرة المقيدة بنطاقات مخصصة حجر الأساس في العديد من النماذج التطبيقية. ففي مجال الهندسة البيئية والأرصاد الجوية، يُستخدم هذا الأسلوب لمحاكاة درجات الحرارة اليومية العشوائية داخل منطقة مناخية معينة تتراوح فيها درجات الحرارة المتوقعة بين 50 و100 درجة فهرنهايت، مما يسمح باختبار تحمل الأنظمة الحرارية في ظل تقلبات واقعية.

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

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

6. المثال 2: توليد أرقام عشوائية مقربة إلى منازل عشرية محددة

6.1 دمج دالة round() مع دالة runif()

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

تأخذ الصيغة التركيبية لهذا التكامل الشكل التالي: round(runif(n, min, max), digits = k)، حيث يمثل الوسيط digits عدد الخانات العشرية المرغوب الاحتفاظ بها بعد الفاصلة. تقوم الدالة الداخلية runif بإنتاج المتجه المستمر بدقته الكاملة أولاً، ثم تتولى الدالة الخارجية round معالجة كل عنصر في المتجه وفقاً لقواعد التقريب المعيارية الدولية (Round half to even)، مما يضمن إزالة التحيز الإحصائي في عمليات التقريب المتكررة.

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

6.2 تنفيذ الشيفرة وتحليل البيانات المقربة

لتطبيق هذا المفهوم عملياً، سنقوم بتوليد 10 قيم عشوائية تقع في النطاق بين 50 و100 مع تقريب المخرجات لمنزلة عشرية واحدة فقط (digits = 1)، مع الاحتفاظ بنفس البذرة العشوائية set.seed(5) لمقارنة النتائج المقربة بالقيم الأصلية غير المقربة التي حصلنا عليها في المثال السابق.

يتم تنفيذ الكود البرمجي كالتالي:

set.seed(5)

rounded_values <- round(runif(n = 10, min = 50, max = 100), digits = 1)

rounded_values

تظهر مخرجات التنفيذ في نافذة بيئة R بالشكل المبسط التالي:

[1] 60.0 84.3 95.8 64.2 55.2 85.1 76.4 90.4 97.8 55.5

يقود تحليل هذه البيانات المقربة إلى جملة من الملاحظات الإحصائية الهامة:

  • المطابقة مع الأصل: نلاحظ أن القيمة الأولى (60.01072) أصبحت (60.0)، والقيمة الثانية (84.26084) تحولت بالتقريب الرياضي الصحيح إلى (84.3)، والقيمة السادسة (85.05141) قُربت إلى (85.1). هذا يوضح أن الدالة نفذت التقريب لأقرب كسر عشري مفرد بدقة متناهية.
  • التحول نحو التقطع الطفيف: من الناحية النظرية الصارمة، يؤدي تطبيق دالة التقريب إلى تحويل التوزيع من كونه “مستمراً تماماً” إلى توزيع “شبه متقطع” (Discretized Continuous Distribution)، حيث أصبحت القيم المحتملة محصورة في شبكة من النقاط المتقطعة التي يفصل بين كل منها مسافة قدرها 0.1 وحدة. ومع ذلك، يظل التوزيع محتفظاً بخاصية الانتظام الاحتمالي عبر هذه النقاط.

6.3 البدائل البرمجية للتقريب: signif() وformat()

توفر بيئة R دوال برمجية بديلة تخدم متطلبات متنوعة للتحكم في الأرقام العشوائية المولدة. من بين هذه البدائل تبرز دالة signif()، والتي تُستخدم للتقريب بناءً على “عدد الأرقام المعنوية الكلية” (Significant Digits) بدلاً من عدد الخانات بعد الفاصلة العشرية. فالأمر signif(runif(1, 50, 100), 3) يضمن بقاء ثلاثة أرقام ذات دلالة إجمالية في العدد الناتج (مثل 78.4 أو 100).

أما عندما يكون الهدف النهائي هو إنتاج مخرجات موجهة للنشر والطباعة وتنسيق المحاذاة في التقارير النصية دون المساس بالبنية العددية المخزنة، فيُفضل استخدام دوال التنسيق النصي مثل format() أو sprintf(). فالأمر sprintf(“%.2f”, runif(5, 50, 100)) يُنتج متجراً نصياً تظهر فيه الأرقام محاطة دائماً بخانتين عشريتين حتى لو كانت الخانات أصفاراً طرفية (مثل “60.00”)، وهو ما يلائم متطلبات التنسيق الصارمة في المجلات العلمية.

من الضروري إدراك الفارق الجوهري بين الدوال: فبينما تحافظ round وsignif على النمط العددي للبيانات (Numeric) وتسمح بإجراء عمليات حسابية لاحقة، تحول دوال format وsprintf الأرقام إلى سلاسل نصية (Characters)، مما يتطلب إعادة تحويلها باستخدام as.numeric() في حال الرغبة بإدراجها في معادلات إحصائية جديدة.

7. المثال 3: توليد أعداد صحيحة عشوائية باستخدام runif ودوال التقريب الأرضي والعلوي

7.1 تحويل التوزيع المستمر إلى أعداد صحيحة متقطعة

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

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

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

floor(runif(n, min = min_val, max = max_val + 1))

إن إضافة الرقم 1 إلى الحد الأعلى داخل runif أمر إلزامي من الناحية الاحتمالية. فإذا أردنا توليد أرقام صحيحة بين 1 و100 وحددنا max = 100 مع دالة floor، فإن القيمة 100 لن تظهر أبداً إلا إذا ولدت الخوارزمية الرقم 100.000000 تماماً (وهو حدث احتماليته تقترب من الصفر رياضياً). وبإضافة 1 ليصبح المجال [1, 101)، تصبح كل فترة [k, k+1) تمتلك اتساعاً متساوياً مقداره 1.0 وحدة كاملة، مما يمنح كل عدد صحيح فرصة ظهور متكافئة تماماً تبلغ 1 / 100.

7.2 التطبيق البرمجي للمثال الثالث

سنطبق هذا البناء الرياضي برمجياً لإنتاج 10 أعداد صحيحة عشوائية تقع في النطاق المغلق بين 1 و100 مع ضبط البذرة العشوائية set.seed(5) لضمان تتبع مسار التنفيذ:

يتم تنفيذ الشيفرة كالتالي:

set.seed(5)

random_integers <- floor(runif(n = 10, min = 1, max = 101))

random_integers

تُسفر هذه العملية عن المخرجات التالية في بيئة R:

[1] 21 69 92 29 11 71 53 81 96 12

يكشف فحص هذه المخرجات عن النقاط التحليلية التالية:

  • استبعاد الكسور التام: تحولت القيم بالكامل إلى أعداد صحيحة نقية خالية تماماً من الفواصل والكسور العشرية، مما يجعلها مطابقة تماماً للمتغيرات المتقطعة.
  • الامتثال للحدود المتقطعة: جميع الأعداد تقع ضمن النطاق [1, 100]، حيث نلاحظ وجود قيم دنيا مثل 11 و12 وقيم عليا مثل 92 و96، دون ظهور أي قيمة شاذة مثل الصفر أو 101.
  • الكفاءة التحويلية: تمت المعالجة عبر عمليات موجهة بالكامل في خطوة واحدة فائقة السرعة، دون الحاجة لبناء حلقات تكرارية لفحص وتقريب كل عنصر على حدة.

7.3 مقارنة دالة runif المعدلة بدالة sample() المخصصة للأعداد الصحيحة

توفر لغة R الدالة الشهيرة sample() لأخذ العينات من المتجهات المتقطعة، كما في الأمر: sample(1:100, size = 10, replace = TRUE). وعلى الرغم من أن sample() تُعد أكثر سهولة في القراءة المباشرة لتوليد الأعداد الصحيحة، إلا أن استخدام floor(runif()) يحمل مزايا معمارية وأداء استثنائي في سيناريوهات برمجية معينة.

عند محاكاة عينات هائلة الحجم تصل إلى مئات الملايين من الملاحظات، تتفوق دالة runif مع floor في استهلاك الذاكرة وسرعة المعالجة؛ إذ لا تتطلب دالة runif إنشاء المتجه المرجعي الأولي وتخزينه في الذاكرة (كما تفعل sample التي تبني المتجه 1:100 أولاً في الرام ثم تسحب منه)، بل تقوم بتوليد التدفق الحسابي مباشرة عبر النواة البرمجية المكتوبة بلغة C.

يوضح الجدول المقارن التالي الفروق الجوهرية بين الأسلوبين:

  • أسلوب floor(runif()): يعتمد على الحساب الرياضي المباشر، لا يستهلك ذاكرة وسيطة لتخزين مجتمع العينة، يولد عينات مع الإرجاع حصراً، ويتفوق في محاكاة العينات الفائقة الحجم والعمليات الحسابية المتوازية.
  • أسلوب sample(): يعتمد على فهرسة العناصر واختيارها، يتطلب تمرير المتجه الأصلي في الذاكرة، يدعم الاختيار مع الإرجاع (replace = TRUE) وبدون إرجاع (replace = FALSE)، ويدعم تمرير أوزان احتمالية غير متساوية عبر المعامل prob.

8. المثال 4: محاكاة مجموعات بيانات وتمثيل التوزيع بصرياً عبر الرسوم البيانية

8.1 توليد مصفوفة بيانات واسعة النطاق (Large-Scale Simulation)

لتوضيح قوة دالة runif في بيئات المحاكاة الإحصائية الواقعية، سنقوم في هذا المثال بمحاكاة مجموعة بيانات واسعة النطاق تتكون من 100,000 قيمة عشوائية مستمرة تتوزع على المجال [0, 50]. الهدف من هذا الحجم الضخم هو إثبات تقارب التوزيع التجريبي الفعلي مع التوزيع النظري المستمر بصورة بيانية وإحصائية لا تقبل الشك وفقاً لقانون الأعداد الكبيرة ونظرية الغايات المركزية.

نقوم بتوليد البيانات وتنظيمها داخل إطار بيانات مهيكل (Data Frame) باستخدام الشيفرة البرمجية التالية:

set.seed(123)

simulated_data <- data.frame(Values = runif(n = 100000, min = 0, max = 50))

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

  • المتوسط الحسابي النظري: E(X) = (0 + 50) / 2 = 25.0000. والمتوسط التجريبي الفعلي للعينة: 24.9912 (نسبة خطأ لا تتجاوز 0.035%).
  • التباين النظري: Var(X) = (50 – 0)^2 / 12 = 2500 / 12 = 208.3333. والتباين التجريبي الفعلي للعينة: 208.1945.
  • الانحراف المعياري النظري: SD(X) = sqrt(208.3333) = 14.4337. والانحراف المعياري التجريبي الفعلي: 14.4289.
  • الحد الأدنى والأعلى: الحد الأدنى الفعلي 0.00032 والحد الأعلى الفعلي 49.99978، مما يغطي كامل النطاق [0, 50] دون أي انحياز.

8.2 التمثيل البصري باستخدام المدرج التكراري (Histogram)

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

يمكن رسم المدرج التكراري الأساسي باستخدام دالة hist() المدمجة، أو بناء مخطط بياني احترافي فائق الدقة باستخدام حزمة ggplot2 الشهيرة، مع ضبط عدد الفئات (bins) وإضافة خط الكثافة النظري المتوقع لمقارنته بالتوزيع التجريبي الفعلي.

runif histogram in R
runif histogram in R

يتم بناء الرسم البياني المتقدم عبر الشيفرة التالية:

library(ggplot2)

ggplot(simulated_data, aes(x = Values)) +
  geom_histogram(aes(y = after_stat(density)), bins = 50, fill = “#3498db”, color = “white”, alpha = 0.8) +
  geom_hline(yintercept = 1/50, color = “#e74c3c”, linetype = “dashed”, linewidth = 1.2) +
  labs(title = “المدرج التكراري للتوزيع المنتظم المستمر (N = 100,000)”,
       subtitle = “مقارنة الكثافة التجريبية الفعلية بخط الكثافة النظري الثابت (f(x) = 0.02)”,
       x = “القيم المولدة”, y = “الكثافة الاحتمالية”) +
  theme_minimal()

يُظهر الرسم البياني الناتج أعمدة تكرارية تكاد تتطابق تماماً في ارتفاعها مع الخط الأفقي المتقطع باللون الأحمر، والذي يمثل الكثافة النظرية الثابتة (1 / (50 – 0) = 0.02). هذا التسطح الأفقي المستقر يقدم دليلاً مرئياً قاطعاً على غياب أي قمم (Peaks) أو تقعرات، مما يؤكد انتظام التوزيع عبر كامل النطاق المدروس.

8.3 التمثيل البصري باستخدام منحنيات الكثافة ومخططات الصندوق

لتعميق الفحص التشخيصي للبيانات المولدة، نلجأ إلى تقنيتين بصريتين إضافيتين: منحنى تقدير الكثافة اللامعلمي (Kernel Density Estimation) ومخطط الصندوق وطرفيه (Boxplot).

باستخدام الأمر geom_density(color = “#2ecc71”, linewidth = 1.1)، نلاحظ أن منحنى الكثافة التجريبي يشكل خطاً أفقياً مستقيماً يمتد بسلاسة من القيمة 0 إلى القيمة 50، مع هبوط رأسي حاد عند الطرفين خارج النطاق. هذا الشكل الصندوقي يثبت رياضياً أن احتمالية ظهور القيم عند الأطراف مساوية تماماً لاحتمالية ظهورها في منتصف النطاق، وهو ما يميز التوزيع المنتظم عن التوزيع الطبيعي الذي يتركز حول المركز.

أما عند إنشاء مخطط الصندوق عبر الأمر geom_boxplot(fill = “#9b59b6”, alpha = 0.7)، نكشف عن مؤشرات هندسية مميزة للتوزيع المنتظم:

  • توسط خط الوسيط: يقع الخط الأسود العريض الممثل للوسيط بدقة تامة في منتصف الصندوق عند القيمة 25، مما يؤكد التماثل التام لبيانات العينة.
  • اتساع المدى الربيعي: تمتد حواف الصندوق من المئين الخامس والعشرين (Q1 = 12.5) إلى المئين الخامس والسبعين (Q3 = 37.5)، محققة مدى ربيعياً نظرياً يغطي بالضبط 50% من طول النطاق الكلي: IQR = 50 – 25 = 25.
  • غياب القيم المتطرفة: تمتد أطراف المخطط (Whiskers) لتصل بدقة إلى الحدين 0 و50 دون ظهور أي نقاط منفردة تتجاوز هذه الحدود، مما يثبت خلو التوزيع المنتظم المستمر من أي قيم شاذة أو متطرفة (Outliers) نظراً لطبيعته المحصورة بصرامة بين الحدين min وmax.

9. تطبيقات متقدمة لدالة runif في المحاكاة والنمذجة الإحصائية والقياس

9.1 تطبيق طريقة مونت كارلو لحساب التكاملات الرياضية والتقديرات الاحتمالية

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

من أشهر التطبيقات الكلاسيكية لمحاكاة مونت كارلو هو التقدير العددي لقيمة الثابت الرياضي الشهير Pi (π). تقوم الفكرة الهندسية على توليد عدد ضخم من النقاط العشوائية الثنائية (x, y) المنتشرة بانتظام داخل مربع يمتد من [0, 1] في كلا البعدين، وحساب نسبة النقاط التي تسقط داخل ربع الدائرة المحددة بالمعادلة x^2 + y^2 ≤ 1.

يتم تنفيذ هذا النموذج الرياضي الرائع عبر الأسطر البرمجية التالية:

N <- 1000000

x <- runif(N, min = 0, max = 1)

y <- runif(N, min = 0, max = 1)

inside_circle <- (x^2 + y^2) ≤ 1

pi_estimate <- 4 * (sum(inside_circle) / N)

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

9.2 توليد توزيعات احتمالية مخصصة عبر التحويل المنتظم (Inverse Transform Sampling)

تُعد مبرهنة “أخذ العينات بالتحويل العكسي” (Inverse Transform Sampling) المنهجية الرياضية المعيارية لتوليد متغيرات عشوائية تتبع أي توزيع احتمالي مستمر، بشرط معرفة مقلوب دالة التوزيع التراكمي الخاصة به F^(-1)(u). وتعتمد هذه التقنية حصراً على توليد أرقام عشوائية منتظمة معيارية U ~ Uniform(0, 1) باستخدام دالة runif، ثم تمريرها داخل الدالة العكسية.

لتطبيق ذلك عملياً، لننظر في توليد متغيرات تتبع “التوزيع الأسي” (Exponential Distribution) بمعلمة معدل λ (Lambda). دالة التوزيع التراكمي للتوزيع الأسي هي F(x) = 1 – e^(-λx). وبحل المعادلة بالنسبة لـ x بدلالة الاحتمال المنتظم u، نحصل على الدالة العكسية:

x = -ln(1 – u) / λ

وحيث إن المتغير (1 – u) يتوزع أيضاً توزيعاً منتظماً معيارياً تماماً مثل u على الفترة [0, 1]، يمكن تبسيط الصيغة البرمجية لتوليد 1000 قيمة تتبع التوزيع الأسي بمعدل λ = 2 كما يلي:

u <- runif(1000)

exp_samples <- -log(u) / 2

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

9.3 محاكاة الاستجابات في القياس النفسي ونماذج اختبارات القدرات

في مجالات القياس النفسي والتربوي (Psychometrics)، تُستخدم نظرية استجابة المفردة (Item Response Theory – IRT) لنمذجة احتمالية إجابة فرد ذي قدرة كامنة محددة (θ) إجابة صحيحة على سؤال اختباري ذي صعوبة معينة (b). وفي نموذج راش أحادي المعلمة (Rasch Model)، تُحسب هذه الاحتمالية P عبر الدالة اللوجستية:

P(θ, b) = exp(θ – b) / (1 + exp(θ – b))

لتحويل هذا الاحتمال النظري المستمر (الذي يتراوح بين 0 و1) إلى استجابة ثنائية واقعية (0 لخطأ، و1 لصواب)، يتم استخدام دالة runif كآلية للمفاضلة العشوائية (Stochastic Thresholding). فإذا كانت القيمة المولدة من runif(1) أقل من الاحتمال P، تُسجل الاستجابة 1، وإلا تُسجل 0.

يمكن محاكاة استجابات 500 طالب على سؤال تبلغ احتمالية حله الصحيح P = 0.70 عبر السطر البرمجي المباشر:

responses <- ifelse(runif(500) < 0.70, 1, 0)

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

10. تحسين الأداء الحسابي والمعالجة الموجهة (Vectorization) مع دالة runif

10.1 مفهوم المعالجة الموجهة وتجنب الحلقات التكرارية (Loops)

صُممت لغة R في جوهرها لتكون لغة معالجة موجهة (Vectorized Language)، حيث تُنفذ العمليات على المتجهات والمصفوفات دفعة واحدة عبر استدعاء دوال داخلية مكتوبة بلغات منخفضة المستوى مثل C وFortran. ويُعد استخدام المعالجة الموجهة مع دالة runif القاعدة الذهبية لتحقيق أعلى مستويات الأداء البرمجي وتفادي البطء الشديد الناتج عن الحلقات التكرارية الكلاسيكية (for loops).

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

يوضح قياس زمن التنفيذ والمقارنة المعيارية باستخدام حزمة microbenchmark هذا الفارق الشاسع:

  • توليد 1,000,000 رقم عشوائي عبر حلقة for متكررة يستغرق عدة ثوانٍ ويستهلك دورات معالجة مكثفة.
  • توليد نفس المليون رقم عبر الاستدعاء الموجه المباشر runif(1000000) يستغرق أجزاء ضئيلة جداً من الثانية (أقل من 0.03 ثانية على معظم المعالجات الحديثة).

هذا التباين الهائل يؤكد ضرورة تجنب تضمين استدعاءات مفردة لـ runif داخل حلقات تكرارية ضخمة، واستبدال ذلك بتوليد المتجه الكامل مسبقاً ثم التعامل معه عبر العمليات الموجهة.

10.2 توليد مصفوفات وأطر بيانات متعددة الأبعاد بكفاءة

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

لبناء مصفوفة عشوائية تتكون من 1000 صف و500 عمود (بإجمالي 500,000 عنصر) تقع قيمها بين -1 و+1، يتم تنفيذ الأمر التالي بكفاءة قصوى:

random_matrix <- matrix(runif(1000 * 500, min = -1, max = 1), nrow = 1000, ncol = 500)

تتميز هذه الطريقة بأنها تقوم بإنشاء المتجه الأولي الموحد وتوزيع أبعاده داخل مصفوفة الذاكرة دفعة واحدة دون أي تكرار وسيط. كما يمكن تطبيق نفس المنهجية لإنشاء أطر بيانات ضخمة (Data Frames) تحتوي على ملايين السجلات عبر تمرير أعمدة متعددة ومولدة بواسطة runif داخل الدالة سريعة الأداء data.table أو tibble، مما يتيح محاكاة قواعد بيانات كاملة بأقل استهلاك لذاكرة النظام.

وعند الانتقال إلى مشاريع المحاكاة العملاقة التي تتطلب مليارات الملاحظات وتتجاوز سعة الذاكرة العشوائية المفردة، يمكن توظيف المعالجة المتوازية عبر تقسيم عملية التوليد إلى كتل متوازية يتم تنفيذها عبر مسارات معالجة متعددة (Multi-threading) باستخدام حزم متقدمة مثل parallel وRcpp لكتابة أجزاء المحاكاة الحساسة مباشرة بلغة ++C مع ربطها بمولدات R.

10.3 إدارة الذاكرة المؤقتة أثناء عمليات المحاكاة الكبيرة

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

تتضمن أفضل الممارسات لإدارة الذاكرة الخطوات المنهجية التالية:

  • الحذف الصريح للكائنات المؤقتة: بمجرد الانتهاء من استخدام متجه عشوائي ضخم (مثل مصفوفة وسيطة)، يجب حذفه فوراً من مساحة العمل باستخدام الدالة rm()، كأن نكتب: rm(large_vector).
  • الاستدعاء اليدوي لجامع المهملات: على الرغم من أن لغة R تقوم بإدارة الذاكرة وتجميع المهملات تلقائياً، إلا أن استدعاء الدالة gc() (Garbage Collection) بعد حذف الكائنات الضخمة يجبر بيئة R على تحرير المساحات المحجوزة فوراً وإعادتها إلى نظام التشغيل.
  • تجنب التكرار غير الضروري للبيانات: يجب تجنب تعديل الكائنات الضخمة داخل دوال فرعية بطريقة تؤدي إلى استنساخ المتجه في الذاكرة وفق مبدأ (Copy-on-modify)، والاعتماد بدلاً من ذلك على التعديل في المكان أو استخدام حزم مثل data.table التي تعدل البيانات مباشرة عبر المؤشرات المرجعية.

11. مقارنة شاملة بين دالة runif ودوال التوزيعات العشوائية الأخرى في R

11.1 مقارنة runif مع rnorm (التوزيع المنتظم مقابل التوزيع الطبيعي)

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

يتميز التوزيع الناتج عن runif بأنه “توزيع محدود ومسطح”؛ حيث يمتلك حدوداً قطعية صارمة محددة بالمعاملين [min, max] لا يمكن تجاوزها، وتتساوى الكثافة الاحتمالية عبر كامل النطاق دون وجود أي قمة أو تمركز حول الوسط. في المقابل، يُنتج التوزيع الطبيعي عبر rnorm توزيعاً “ناقوسياً متماثلاً غير محدود” يمتد نظرياً من سالب ما لا نهاية إلى موجب ما لا نهاية (-∞, +∞)، وتتمركز أعلى كثافة احتمالية له حول المتوسط الحسابي (mean) مع تناقص تدريجي سريع في الذيول يتحدد بقيمة الانحراف المعياري (sd).

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

11.2 مقارنة runif مع sample وrbinom

عند مقارنة runif بدالتي sample وrbinom، ننتقل من فضاء التوزيعات المستمرة إلى فضاء التوزيعات المتقطعة والتجارب الثنائية المنفصلة.

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

أما دالة rbinom فتختص بمحاكاة “توزيع ذي الحدين” (Binomial Distribution)، والذي يصف عدد مرات النجاح المتحققة في سلسلة من تجارب برنولي المستقلة (n من المحاولات باحتمال نجاح p). تُنتج rbinom أعداداً صحيحة تمثل التكرارات الناجحة، في حين أن runif تُنتج تدفقاً مستمراً من القيم الحقيقية. ومع ذلك، يمكن بناء تجارب برنولي الثنائية اعتماداً على runif عبر المقارنة الشرطية: as.numeric(runif(N) < p)، وهو ما يوضح مجدداً القوة التأسيسية لدالة التوزيع المنتظم في بناء التوزيعات الأخرى.

11.3 جدول مقارن للخصائص الإحصائية والمعايير البرمجية

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

اسم الدالة التوزيع الاحتمالي طبيعة المتغير الوسائط الأساسية الافتراضية المجال الرياضي للقيم الاستخدام المنهجي الأمثل
runif التوزيع المنتظم (Uniform) مستمر (Continuous) n, min = 0, max = 1 [min, max] (محدود) المحاكاة العشوائية، طرق مونت كارلو، التحويل الاحتمالي العكسي
rnorm التوزيع الطبيعي (Gaussian) مستمر (Continuous) n, mean = 0, sd = 1 (-∞, +∞) (غير محدود) نمذجة الظواهر الطبيعية، أخطاء القياس، اختبار الفرضيات
rbinom توزيع ذي الحدين (Binomial) متقطع (Discrete) n, size, prob {0, 1, 2, …, size} تجارب برنولي، محاكاة النجاح والفشل، معدلات التحويل
rpois توزيع بواسون (Poisson) متقطع (Discrete) n, lambda {0, 1, 2, …} نمذجة معدلات الوصول، الأحداث النادرة، فترات الانتظار
sample اختيار عينات تجريبية متقطع / نصي / مختلط x, size, replace = FALSE, prob = NULL عناصر المتجه x المدخل إعادة أخذ العينات، بوتستراب، تقسيم مجموعات البيانات

12. الأخطاء الشائعة، المحاذير البرمجية، وأفضل الممارسات عند استخدام runif

12.1 الخلط بين الحدود المفتوحة والمغلقة للفترات الاحتمالية

من الأخطاء المفاهيمية الشائعة بين الباحثين والمبرمجين الخلط بين السلوك النظري للتوزيع المنتظم المستمر والسلوك الحسابي الفعلي للتمثيل الرقمي في الحواسيب. من الناحية النظرية الرياضية الصارمة، فإن احتمالية أن تأخذ دالة الكثافة المستمرة قيمة محددة بدقة متناهية تساوي صفراً: P(X = min) = 0 و P(X = max) = 0، وبالتالي لا يوجد فرق رياضي بين الفترة المغلقة [a, b] والفترة المفتوحة (a, b).

ومع ذلك، من الناحية الحاسوبية والبرمجية، يعتمد مولد الأرقام على تمثيل الفاصلة العائمة المزدوجة (IEEE 754 floating-point standard). وتولد خوارزمية Mersenne-Twister في لغة R قيماً تقع عادة في الفترة شبه المفتوحة [0, 1)، مما يعني أن القيمة الدنيا 0.0 يمكن أن تظهر حسابياً، بينما القيمة العليا 1.0 لا تظهر عملياً في التوليد المعياري.

قد يؤدي هذا السلوك الحسابي الدقيق إلى أخطاء برمجية كارثية إذا اعتمد المطور على ناتج runif كقاسم في عملية حسابية مباشرة (مثل: 1 / runif(1))، حيث إن ظهور القيمة 0.0 سيؤدي فوراً إلى القسمة على الصفر وإنتاج مالا نهاية (Inf). كما قد يسبب مشاكل عند استخدام القيمة المولدة كمؤشر فهرسة لمصفوفة. ولتفادي هذه المحاذير، يجب فحص القيم المولدة وكتابة شروط حماية منطقية تمنع العمليات غير المعرفة عند الحواف الصفرية.

12.2 أخطاء التعامل مع وسائط الدالة وتمرير المتجهات الخاطئة

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

إذا قمت بتمرير متجه كالتالي: runif(5, min = c(0, 10), max = 100)، ستقوم لغة R بتطبيق آلية إعادة التدوير، حيث ستولد القيمة الأولى بالحد الأدنى 0، والثانية بالحد الأدنى 10، والثالثة بالحد الأدنى 0، وهكذا، مع إطلاق تحذير فقط إذا لم تكن الأطوال مضاعفات لبعضها. هذا التدوير الصامت قد يفسد تجارب المحاكاة إذا لم يكن مقصوداً من المبرمج.

كذلك يؤدي تمرير قيم مفقودة (NA) أو قيم غير عددية (NaN / NULL) إلى وسائط الدالة إلى فشل التوليد وإنتاج متجهات مفقودة. ولتجنب هذه المشكلات، يُنصح بتطبيق مبادئ “البرمجة الدفاعية” (Defensive Programming) عبر فحص المدخلات والتأكد من صحتها المنطقية باستخدام دوال التحقق مثل stopifnot() قبل استدعاء التوليد، كالتالي:

stopifnot(is.numeric(n), n > 0, length(min) == 1, length(max) == 1, min < max)

12.3 الدليل الإرشادي لأفضل الممارسات البرمجية المعتمدة

لكتابة شيفرات برمجية تتسم بأعلى معايير الجودة العلمية والموثوقية الهندسية عند استخدام دالة runif، يُوصى باتباع الدليل الإرشادي والقواعد التنفيذية التالية:

  • التوثيق الإلزامي للبذور العشوائية: احرص دائماً على تسجيل وتوثيق قيمة البذرة المستخدمة set.seed() في مقدمة السكربت الإحصائي وتدوينها صراحة في منهجية الأوراق البحثية والتقارير العلمية لضمان قابلية إعادة الإنتاج والتدقيق المستقل.
  • استخدام التسمية الصريحة للوسائط (Explicit Argument Naming): اكتب دائماً أسماء المعاملات صراحة (مثل: runif(n = 100, min = 10, max = 50)) وتجنب الاعتماد على الترتيب الضمني (مثل: runif(100, 10, 50)). هذا يعزز وضوح الشيفرة ويمنع الخلط العرضي بين الحد الأدنى والأعلى.
  • الاعتماد الكامل على المعالجة الموجهة: تجنب نهائياً توليد القيم العشوائية داخل حلقات for أو while، وقم بتوليد المتجه الحسابي كاملاً بحجم n المطلوب دفعة واحدة لتحقيق أقصى استفادة من محرك C الداخلي في لغة R.
  • الفصل بين التوليد والتحويل التنسيقي: احتفظ دائماً بالمتجه العشوائي الخام بدقته الكاملة في كائن منفصل لإجراء العمليات الإحصائية وحساب العزوم، وقم بتطبيق دوال التقريب والتنسيق (مثل round وformat) على كائنات جديدة مخصصة للعرض والطباعة فقط.
  • هيكلة سكربتات المحاكاة بشكل تركيبي: قسّم مشاريع المحاكاة المعقدة إلى دوال مخصصة (Custom Functions) تأخذ المعلمات الإحصائية كمدخلات وترجع النتائج في هياكل بيانات مهيكلة، مما يسهل صيانتها واختبارها وإعادة استخدامها في مشاريع برمجية مستقبلية.

خاتمة

استعرضنا في هذا الدليل الشامل والموسع كافة الأبعاد النظرية والتطبيقية المرتبطة باستخدام دالة runif في لغة R. انطلقنا من الأسس الرياضية والخوارزمية للتوليد شبه العشوائي ومولد Mersenne-Twister، مروراً بالخصائص الدقيقة لدالة الكثافة والتوزيع التراكمي للتوزيع المنتظم المستمر، وتشريح وسائط الدالة وآليات ضبط البذور العشوائية لضمان تكرارية النتائج ونزاهتها العلمية.

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

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

References

اقتباس هذا المقال

looti, M. (2026, سبتمبر 1). كيفية استخدام دالة runif في لغة R (4 أمثلة). عرب سايكلوجي. https://arabpsychology.com/statistics/how-to-use-runif-function-in-r-examples/
looti, Mohammed. “كيفية استخدام دالة runif في لغة R (4 أمثلة).” عرب سايكلوجي, 1 سبتمبر 2026, https://arabpsychology.com/statistics/how-to-use-runif-function-in-r-examples/.
looti, Mohammed. “كيفية استخدام دالة runif في لغة R (4 أمثلة).” عرب سايكلوجي. سبتمبر 1, 2026. https://arabpsychology.com/statistics/how-to-use-runif-function-in-r-examples/.