الإحصاء التطبيقي, برمجة R, تحليل البيانات

كيفية حساب المتوسط المتحرك في R (مع مثال)


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

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

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

1. مقدمة إلى مفهوم المتوسط المتحرك في تحليل السلاسل الزمنية

1.1 التعريف الإحصائي للمتوسط المتحرك (Rolling Average)

يُعرَّف المتوسط المتحرك إحصائياً بأنه مقياس تجميعي ديناميكي يُحسب لمجموعة فرعية متتالية من نقاط البيانات داخل سلسلة زمنية معينة، حيث تتحرك هذه المجموعة الفرعية—المعروفة بـ “نافذة المراقبة” (Rolling Window)—بمعدل خطوة واحدة زمنياً للأمام عبر كامل نطاق السلسلة. وخلافاً للمتوسط الحسابي العام التقليدي (Global Mean) الذي يختزل السلسلة الزمنية بأكملها في قيمة عددية وحيدة ثابتة تمثل مركز التوزيع الكلي وتفقد تماماً البعد الزمني والحركي للظاهرة، يقوم المتوسط المتحرك بتوليد متتالية جديدة من القيم الموضعية المتتابعة التي تعكس التغير المحلي لمركز الثقل الإحصائي عبر كل فترة جزئية محددة.

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

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

1.2 أهمية تمهيد البيانات (Data Smoothing) في لغة R

يمثل تمهيد البيانات (Data Smoothing) ركيزة منهجية لا غنى عنها في هندسة الخصائص الإحصائية والتحليل الاستكشافي للسلاسل الزمنية المبرمجة بلغة R. تبرز أهمية هذه العملية أولاً في تسهيل “تحديد الاتجاه العام” (Trend Identification)، حيث تعاني السلاسل الزمنية الواقعية من تراكب مركبات متعددة؛ فالإشارة الإحصائية تتكون بنيوياً من الاتجاه العام، والتأثيرات الموسمية، والتذبذبات الدورية، والخطأ العشوائي المتبقي. ومن خلال تطبيق خوارزميات التنعيم المتحركة، يستطيع المحلل عزل المركب الاتجاهي طويل الأجل بدقة، مما يتيح رؤية المسار التصاعدي أو التنازلي الحقيقي للظاهرة دون تشتيت ناجم عن التقلبات اليومية.

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

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

1.3 حالات الاستخدام الشائعة للمتوسطات المتحركة

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

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

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

2. المفاهيم الرياضية والإحصائية خلف النوافذ المتحركة

2.1 الصيغة الرياضية لحساب المتوسط المتحرك البسيط (SMA)

يرتكز المتوسط المتحرك البسيط (Simple Moving Average – SMA) على الامتداد الخطي المباشر لمفهوم الوسط الحسابي. إذا افترضنا وجود سلسلة زمنية أحادية البعد يُرمز لقيمها بالمتجه $X = {x_1, x_2, x_3, dots, x_N}$ حيث يمثل $N$ الحجم الكلي للمشاهدات، ونرغب في حساب المتوسط المتحرك البسيط باستخدام نافذة مراقبة ذات عرض زمني قدره $k$ (حيث $k le N$)، فإن القيمة التقديرية للمتوسط المتحرك عند النقطة الزمنية $t$ تُحسب وفقاً للمعادلة الجبرية التالية:

$$\text{SMA}_t = \frac{1}{k} \sum_{i=0}^{k-1} x_{t-i} = \frac{x_t + x_{t-1} + x_{t-2} + dots + x_{t-k+1}}{k}$$

توضح هذه الصيغة الرياضية أن كل قيمة داخل النافذة الزمنية تحصل على وزن نسبي متساوٍ تماماً مقداره $\frac{1}{k}$. يتميز هذا التوزيع المتساوي للأوزان بالبساطة الرياضية وسهولة التأويل الإحصائي، إلا أنه يفرض افتراضاً ضمنياً بأن المشاهدة الأقدم داخل النافذة تمتلك نفس القوة الإخبارية والأهمية التفسيرية التي تمتلكها أحدث مشاهدة تم رصدها، وهو افتراض قد لا يكون دقيقاً دائماً في بعض السلاسل الزمنية شديدة الديناميكية.

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

2.2 مقارنة بين أنواع المتوسطات المتحركة

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

  • المتوسط المتحرك البسيط (Simple Rolling Average): يوزع الأوزان بالتساوي على كافة عناصر النافذة ($w_i = \frac{1}{k}$). يتميز بالسهولة الحسابية والتطبيقية، ولكنه يعاني من مشكلة “أثر القفزة المزدوجة”؛ حيث يتأثر المتوسط مرتين بقيمة متطرفة واحدة: مرة عند دخولها النافذة ومرة أخرى عند خروجها منها.
  • المتوسط المتحرك الموزون (Weighted Rolling Average – WMA): يعالج قصور النموذج البسيط من خلال تخصيص أوزان تراجعية تتناقص خطياً كلما اتجهنا نحو الماضي داخل النافذة. وتُحسب أوزانه وفقاً لمعامل ترجيحي $w_i = \frac{k – i}{\sum_{j=1}^k j}$، مما يمنح المشاهدات الأحدث وزناً ترجيحياً أكبر، ويقلل بالتالي من زمن التأخر في الاستجابة للمتغيرات الحديثة.
  • المتوسط المتحرك الأسي (Exponential Rolling Average – EMA): يعتمد على ترجيح أسي لا نهائي يتلاشى تدريجياً، حيث تُحسب قيمته كدالة تكرارية: $\text{EMA}_t = \alpha \cdot x_t + (1 – \alpha) \cdot \text{EMA}_{t-1}$، حيث يمثل $\alpha$ معامل التنعيم المحصور بين 0 و 1 ($0 < \alpha le 1$). يتميز المتوسط الأسي بعدم حاجته لتخزين نافذة ثابتة من البيانات القديمة، وتجاوبه الفوري والسلس مع الصدمات الحديثة دون إحداث انقطاعات مفاجئة عند التخلص من البيانات السابقة.

2.3 تأثير حجم نافذة المراقبة (Parameter k) على النتائج

يمثل تحديد المعامل $k$ المعضلة الأساسية لما يُعرف إحصائياً بـ “معضلة الموازنة بين التحيز والتباين” (Bias-Variance Tradeoff) في مجال تنعيم البيانات. يؤدي اختيار قيمة صغيرة للبارامتر $k$ إلى إنتاج مقدر منخفض التحيز (Low Bias) يعكس بدقة القمم والقيعان الحقيقية للسلسلة، إلا أنه يتصف بتباين مرتفع (High Variance) نتيجة تأثره بالتقلبات العشوائية. في المقابل، يؤدي اختيار قيمة كبيرة لـ $k$ إلى تقليل التباين بشكل كبير وخلق مسار فائق التجانس (Smoothness)، ولكنه يُدخل تحيزاً هيكلياً يتمثل في حدوث “تأخر زمني ملحوظ” (Time Lag Effect)، حيث ينزاح خط المتوسط زمنياً إلى اليمين متأخراً عن السلسلة الفعلية بمقدار يقارب $\frac{k-1}{2}$ فترة زمنية في المتوسطات المتحركة المحاذاة لليمين.

تستند معايير اختيار $k$ المثلى إلى فهم الطبيعة الفيزيائية أو السلوكية للظاهرة المدروسة والهدف التحليلي الأساسي. فإذا كان الهدف هو عزل الدورة الأسبوعية، فإن $k=7$ (للبيانات اليومية) يمثل الخيار المنهجي الإلزامي رياضياً لإلغاء التذبذب الداخلي للأسبوع. وإذا كانت البيانات ربع سنوية وتهدف لعزل الأثر السنوي، فإن $k=4$ يكون الخيار البديهي.

تكمن المخاطر الإحصائية الكبرى في “الإفراط في التنعيم” (Over-smoothing) الناتج عن تضخيم $k$ دون مبرر نظري، مما يؤدي إلى طمس الإشارات الحيوية، وتسطيح القمم الهامة، وإلغاء نقاط الانعطاف الهيكلية في السلسلة الزمنية، مما يقود إلى استنتاجات مضللة تماماً حول توقيت وحجم التغيرات في الظاهرة محل الرصد.

3. إعداد بيئة العمل البرمجية وتثبيت الحزم في R

3.1 تثبيت واستدعاء الحزم الضرورية (zoo و dplyr)

لتنفيذ العمليات الإحصائية الخاصة بالمتوسطات المتحركة بكفاءة واستقرار برمجي، نعتمد على حزمتين أساسيتين من أقوى حزم منظومة R الإحصائية: حزمة zoo وحزمة dplyr. تُعد حزمة zoo (المشتق اسمها من اختصار Z’s Ordered Observations) الحزمة المعيارية الرائدة عالمياً في إدارة ومعالجة الكائنات والمصفوفات المرتبة زمنياً وغير المنتظمة؛ حيث توفر بنية تحتية رياضية عالية الأداء لحساب العمليات الانزلاقية عبر متجهات البيانات. في المقابل، تشكل حزمة dplyr النواة الصلبة لمعالجة وتعديل الجداول والبيانات المهيكلة ضمن بيئة Tidyverse الحديثة، وتوفر صياغة برمجية بديهية وسريعة لإجراء التحويلات الحسابية وإعادة تشكيل الأعمدة عبر المعامل الأنبوبي (Pipe Operator).

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

# تثبيت الحزم الأساسية من مستودع CRAN الرسمي
install.packages("zoo")
install.packages("dplyr")
# استدعاء الحزم البرمجية إلى بيئة العمل الحالية
library(zoo)
library(dplyr)

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

3.2 التكامل بين Tidyverse ومكتبات السلاسل الزمنية

يمثل التكامل البرمجي بين دوال حزمة zoo ومنظومة Tidyverse—وتحديداً حزمة dplyr—أحد أقوى أنماط البرمجة الوظيفية المتبعة في علم البيانات الإحصائي المعاصر. يتيح مفهوم “البيانات المنظمة” (Tidy Data Architecture) هيكلة الجداول الإحصائية بحيث يمثل كل صف مشاهدة زمنية محددة، ويمثل كل عمود متغيراً مقاساً مستقلاً. يتيح هذا النمط دمج دوال النوافذ المتحركة مثل rollmean() بسلاسة فائقة داخل سلاسل العمليات البرمجية المعبر عنها بواسطة المعامل الأنبوبي التقليدي %>% أو المعامل الأصلي الجديد للغة R وهو |>.

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

من الضروري الانتباه عند دمج حزم متعددة إلى مسألة “تعارض أسماء الدوال المشتركة” (Namespace Collisions)؛ فعلى سبيل المثال، تحتوي كل من حزمة dplyr وحزمة stats الأساسية على دوال تحمل أسماء متطابقة مثل filter أو lag. يُنصح المحللون دائماً بتبني أفضل الممارسات البرمجية عبر تحديد النطاق الصريح للدوال (Explicit Namespacing) باستخدام المشغل :: (مثل كتابة dplyr::mutate() أو zoo::rollmean()) لتجنب أي سلوك حسابي غير متوقع ولضمان إمكانية إعادة إنتاج النتائج التحليلية (Reproducibility) عبر مختلف البيئات والأجهزة.

4. التشريح الدقيق لدالة rollmean() في حزمة zoo

4.1 المدخلات الأساسية للدالة (Arguments Overview)

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

rollmean(x, k, fill = if (na.pad) NA, na.pad = FALSE, 
 align = c("center", "left", "right"), 
 only.complete = TRUE, ...)

تستقبل الدالة مجموعة من المدخلات الجوهرية التي تحدد مسار المعالجة الحسابية بدقة متناهية:

  • x: المتجه العددي الهدف (Numeric Vector) أو مصفوفة السلسلة الزمنية المراد تنعيمها. يجب أن تكون البيانات من نوع عددي (Numeric أو Integer).
  • k: عدد صحيح موجب يمثل حجم نافذة المراقبة (Window Width). يحدد هذا البارامتر عدد المشاهدات المتتالية التي ستدخل في حساب كل متوسط محلي.
  • align: معامل توصيف المحاذاة الهندسية للنافذة نسبةً للنقطة المرجعية الحالية، ويقبل ثلاث قيم حرفية أساسية: "right" أو "center" أو "left".
  • fill: المعامل المسؤول عن تحديد كيفية إدارة الأطراف والحدود الزمنية الناتجة عن نقص المشاهدات الكافية لتكوين نافذة كاملة، ويقبل متجهات ملء مثل NA أو أرقاماً مخصصة أو القيمة الافتراضية NULL (أو ضبط na.pad = TRUE في الصياغات الكلاسيكية).
  • na.rm: معامل منطقي (Logical: TRUE أو FALSE) يُمرر للعمليات الداخلية لتحديد ما إذا كان يجب استبعاد القيم المفقودة الفردية داخل النافذة قبل إجراء عملية القسمة الحسابية.

4.2 تحليل سلوك المعامل align (Right, Center, Left)

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

المحاذاة اليمينية (align = "right"): تُسند القيمة المحسوبة في هذه الحالة إلى الطرف الأيمن (النقطة الأخيرة) من النافذة الزمنية. هذا يعني أن المتوسط المتحرك عند اللحظة $t$ يمثل متوسط القيم من $t – k + 1$ إلى $t$. يُعد هذا الخيار هو المعيار الرياضي الصارم في التحليلات التنبؤية، ومراقبة الجودة اللحظية، والأسواق المالية؛ لأنه يعتمد حصراً على البيانات التاريخية المتاحة حتى اللحظة الآنية، مما يمنع تماماً الوقوع في خطأ “تسريب البيانات المستقبلية” (Look-ahead Leakage).

المحاذاة المركزية (align = "center"): يتموضع المتوسط المحسوب في المركز الهندسي الدقيق للنافذة الزمنية؛ أي أن القيمة عند النقطة $t$ تمثل متوسط المشاهدات المتناظرة قبلها وبعدها بالتساوي. يتطلب هذا النمط عادة أن تكون قيمة $k$ عدداً فردياً ($k = 2m + 1$) لتوزيع $m$ مشاهدة على اليمين و $m$ مشاهدة على اليسار. يُفضل استخدام المحاذاة المركزية في الدراسات الوصفية الاسترجاعية (Retrospective Descriptive Analysis) وتفكيك السلاسل الزمنية التاريخية لعزل الاتجاهات الكلية دون إحداث إزاحة طورية (Phase Shift) أو تأخير زمني مصطنع في مسار المنحنى.

المحاذاة اليسارية (align = "left"): تُسند القيمة المحسوبة إلى النقطة الأولى (الطرف الأيسر) من النافذة الزمنية، مما يعني أن المتوسط عند النقطة $t$ يعبر عن متوسط النقطة الحالية والنقاط المستقبلية التالية لها حتى $t + k – 1$. يُستخدم هذا النمط في الدراسات الاستشرافية لتقييم الآثار اللاحقة (Forward-looking Evaluation) لمثيرات تجريبية محددة وقعت عند النقطة $t$.

4.3 استراتيجيات التعامل مع المعامل fill

عند تحريك نافذة ذات عرض $k$ عبر سلسلة طولها $N$، لا تتوفر شروط النافذة الكاملة لعدد $k – 1$ من النقاط عند حواف السلسلة. وهنا تبرز أهمية المعامل fill لتحديد البنية الهندسية للمتجه الناتج والتحكم في تطابق أطوال البيانات:

إذا تُرك المعامل بقيمته الافتراضية fill = NULL (دون تفعيل الوسيط na.pad)، فإن الدالة ستتجاهل الحواف تماماً وستُرجع متجهاً مبتوراً بطول $N – k + 1$. على سبيل المثال، تطبيق نافذة $k=3$ على سلسلة من 10 قيم سينتج متجهاً بطول 8 قيم فقط. يؤدي هذا البتر إلى صعوبة تقنية بالغة عند محاولة دمج العمود الناتج مباشرة داخل إطار البيانات الأصلي (Data Frame) باستخدام دوال مثل dplyr::mutate()، حيث يشترط R تطابق أطوال الأعمدة داخل الجدول، وسيؤدي عدم التطابق إلى توليد خطأ فوري (Error: Column length mismatch).

لتفادي هذا الخلل البرمجي، يتم تعيين المعامل fill = NA. يوجه هذا الخيار الدالة لملء الفجوات الحسابية عند الأطراف غير المكتملة بقيم مفقودة NA، مما يضمن أن يكون طول المتجه المخرج مساوياً تماماً لطول المتجه المدخل $N$. يتيح ذلك إدراج عمود المتوسط المتحرك بسلاسة تامة جنباً إلى جنب مع المتغيرات الأصلية داخل قواعد البيانات دون كسر التناسق الهيكلي للبيانات.

5. بناء مجموعة البيانات التجريبية (Data Frame Creation)

5.1 تصميم جدول البيانات الأساسي في R

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

نقوم بإنشاء إطار البيانات الأساسي df باستخدام الدالة المدمجة القياسية data.frame()، حيث نحدد عمود الأيام كمتغير ترتيبي زمني، وعمود المبيعات كمتغير كمي مستمر بوحدات قياسية واضحة:

# إنشاء إطار البيانات التجريبي لمبيعات 10 أيام متتالية
df <- data.frame(
 day = 1:10,
 sales = c(12, 15, 18, 14, 16, 20, 24, 22, 25, 28)
)
# عرض محتوى الجدول التجريبي في نافذة النتائج
print(df)

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

5.2 فحص بنية البيانات والتأكد من توافق الأنواع

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

# فحص البنية التركيبية للجدول وأنواع المتغيرات
str(df)
# استخراج ملخص الإحصاء الوصفي للسلسلة التجريبية
summary(df)

تؤكد مخرجات الدالة str(df) أن الجدول يحتوي على 10 مشاهدات موزعة على متغيرين اثنين من النوع العددي (integer أو numeric). ويكشف الفحص الوصفي عبر summary(df) أن متوسط المبيعات الكلي عبر فترة العشرة أيام يبلغ $19.40$ وحدة، بقيمة دنيا قدرها $12$ وقيمة قصوى قدرها $28$. كما يؤكد الفحص خلو البيانات تماماً من أي قيم شاذة غير منطقية أو قيم مفقودة أولية، فضلاً عن ثبات التدرج الزمني التصاعدي لعمود الأيام بفارق منتظم قدره يوم واحد بين كل صف والذي يليه، وهو شرط أساسي لضمان صحة تأويل النوافذ الزمنية المنتظمة.

6. التطبيق العملي: حساب المتوسط المتحرك لثلاثة أيام

6.1 تطبيق الدالة باستخدام dplyr::mutate

نصل الآن إلى مرحلة التطبيق العملي الأساسي؛ حيث سنقوم بحساب المتوسط المتحرك للمبيعات لنافذة زمنية قدرها ثلاثة أيام ($k = 3$). سنعتمد المحاذاة اليمينية (align = "right") لضمان أن كل قيمة محسوبة تعكس متوسط اليوم الحالي واليومين السابقين له حصراً، وهو النمط الأكثر أماناً واستخداماً في التقارير التحليلية والمالية. وسنستخدم fill = NA لضمان الحفاظ على أبعاد الجدول متسقة.

نربط جدول البيانات عبر المعامل الأنبوبي %>% مع دالة mutate() لإنشاء عمود تحليلي جديد يُسمى avg_sales3، ونقوم بتخزين الناتج في إطار بيانات جديد أو إعادة تحديث الجدول الأصلي:

# حساب المتوسط المتحرك لـ 3 أيام بمحاذاة يمينية وتوليد عمود جديد
df_calculated <- df %>%
 dplyr::mutate(
 avg_sales3 = zoo::rollmean(sales, k = 3, fill = NA, align = "right")
 )
# طباعة إطار البيانات المحدث لاستعراض النتائج الحسابية
print(df_calculated)

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

6.2 تفسير المخرجات الحسابية خطوة بخطوة

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

اليوم (day) المبيعات الأصلية (sales) المتوسط المتحرك لـ 3 أيام (avg_sales3) العملية الحسابية الرياضية والتعليل المنهجي
1 12 NA قيمة مفقودة؛ لعدم توفر نقطتين سابقتين لإكمال نافذة الـ 3 أيام.
2 15 NA قيمة مفقودة؛ تتوفر فقط نقطتان (12، 15) والنافذة تتطلب 3 نقاط كاملة.
3 18 15.00000 $\frac{12 + 15 + 18}{3} = \frac{45}{3} = 15.00$ (اكتمال أول نافذة كاملة)
4 14 15.66667 $\frac{15 + 18 + 14}{3} = \frac{47}{3} \approx 15.67$ (خروج اليوم 1 ودخول اليوم 4)
5 16 16.00000 $\frac{18 + 14 + 16}{3} = \frac{48}{3} = 16.00$
6 20 16.66667 $\frac{14 + 16 + 20}{3} = \frac{50}{3} \approx 16.67$
7 24 20.00000 $\frac{16 + 20 + 24}{3} = \frac{60}{3} = 20.00$
8 22 22.00000 $\frac{20 + 24 + 22}{3} = \frac{66}{3} = 22.00$
9 25 23.66667 $\frac{24 + 22 + 25}{3} = \frac{71}{3} \approx 23.67$
10 28 25.00000 $\frac{22 + 25 + 28}{3} = \frac{75}{3} = 25.00$

يوضح هذا الجدول بجلاء كيف تؤدي المحاذاة اليمينية إلى ملء الصفين الأول والثاني بقيم NA؛ حيث يتطلب حساب المتوسط لنافذة $k=3$ توفر المشاهدة الحالية ومشاهدتين سابقتين، وهو ما لا يتحقق إلا بدءاً من الصف الثالث (اليوم الثالث). كما يوضح الجدول كيف تتحرك النافذة بانتظام عبر إسقاط المشاهدة الأقدم وإدراج المشاهدة الأحدث، مما يحقق التمهيد التراكمي المستمر للسلسلة.

6.3 التحقق من صحة الكود وسلامة التوليد

يقتضي التدقيق المنهجي البرمجي مقارنة المخرجات التي ولدتها دالة zoo::rollmean() بالحسابات الحسابية المعيارية للتحقق من عدم حدوث أي انزياح صفي غير مقصود (Unintended Row Shift) أو أخطاء تقريب رقمي. يمكننا استخدام اختبارات الفحص الشرطي البرمجية عبر دالة all.equal() للتأكد من المطابقة التامة بين الحساب البرمجي والمعادلة الرياضية المباشرة لليوم الثالث على سبيل المثال:

# التحقق البرمجي من دقة حساب اليوم الثالث
calculated_val <- df_calculated$avg_sales3[3]
manual_val <- mean(df$sales[1:3])
# التحقق من المطابقة الرياضية التامة
is_matching <- all.equal(calculated_val, manual_val)
print(paste("هل تتطابق القيمة المحسوبة برمجياً مع الحساب اليدوي؟", is_matching))
# فحص أطوال الأعمدة وسلامة البنية النهائية
stopifnot(nrow(df_calculated) == nrow(df))
print("تم التحقق بنجاح: تطابق هيكلي تام وخلو من الإزاحات غير المرغوبة.")

تؤكد هذه الاختبارات التأكيدية أن الخوارزمية نفذت العملية بدقة حسابية مطلقة، وأن عملية التوليد احتفظت بالتوافق الرأسي التام مع مؤشرات الأيام الأصلية دون أي خلل هيكلي.

7. معالجة محاذاة النوافذ الزمنية (Window Alignment Strategies)

7.1 المحاذاة اليمينية (Right Alignment) وسيناريوهات الاستخدام

تعتبر المحاذاة اليمينية (align = "right")—والتي تسمى أحياناً في بعض الأدبيات الإحصائية بالمحاذاة الراجعة (Backward Moving Average)—الخيار الأوحد المسموح به منهجياً عند التعامل مع المسائل التنبؤية الحية ومراقبة العمليات الإنتاجية اللحظية. يعود السبب الأساسي في ذلك إلى المبدأ السببي في الفيزياء والإحصاء؛ فالقيمة التقديرية للظاهرة عند اللحظة $t$ يجب ألا تتأثر إلا بالأحداث والمعلومات التي وقعت بالفعل في الزمن $s le t$.

يؤدي استخدام أي محاذاة أخرى غير اليمينية في التطبيقات التنبؤية إلى الوقوع في خطأ معرفي فادح يُعرف بـ “انحياز التطلع المستقبلي” (Look-ahead Bias)، حيث يستعير النموذج الإحصائي قيماً من المستقبل لتمهيد الحاضر، مما يُعطي نتائج تقييم خادعة وأداءً ممتازاً ظاهرياً أثناء الاختبار بأثر رجعي، ينهار فور تطبيقه على بيانات واقعية حية لم تقع أحداثها بعد. تظهر قيم NA وفق هذا النمط دائماً في “بداية” السلسلة الزمنية بعدد $k-1$ صفاً.

7.2 المحاذاة المركزية (Center Alignment) للتحليل الوصفي

تُمثل المحاذاة المركزية (align = "center") الخيار الإحصائي الأمثل للدراسات الوصفية الاستعادية واستخراج الأنماط التاريخية التي لا تستهدف بناء قرارات تنبؤية فورية في الزمن الحقيقي. الميزة الرياضية الكبرى للمحاذاة المركزية هي “انعدام الإزاحة الطورية” (Zero Phase Shift)؛ حيث يتطابق مركز ثقل النافذة الحسابية تماماً مع النقطة الزمنية المرصودة، مما يمنع انزياح المنحنى الممهد إلى اليمين ويحافظ على التموضع الزمني الدقيق للقمم والقيعان التاريخية.

يُشترط رياضياً في المحاذاة المركزية أن يكون حجم النافذة $k$ عدداً فردياً موجباً ($k = 3, 5, 7, dots$)، وذلك لضمان وجود نقطة مركزية هندسية وحيدة تتوسط النافذة، محاطة بعدد متساوٍ من النقاط على كلا الجانبين مقداره $\frac{k-1}{2}$. عند تطبيق هذا النمط، تتوزع قيم NA غير المحسوبة بالتساوي التام بين أطراف السلسلة؛ حيث يظهر $\frac{k-1}{2}$ من قيم NA في بداية السلسلة، ويظهر عدد مماثل من قيم NA في نهايتها المطلقة.

7.3 المحاذاة اليسارية (Left Alignment) للأغراض الاستشرافية

تُعد المحاذاة اليسارية (align = "left")—أو المحاذاة المتقدمة (Forward Moving Average)—نمطاً متخصصاً يُستخدم في تصميم التجارب المخبرية والدراسات الطولية المتخصصة في قياس التأثيرات اللاحقة للمتغيرات المستقلة. في هذا النمط، تُسند القيمة المحسوبة إلى بداية الفترة الزمنية؛ مما يعني أن المتوسط عند اليوم $t$ يُخبرنا بما سيكون عليه متوسط المشاهدات خلال الأيام القادمة حتى $t + k – 1$.

تتولد قيم NA في المحاذاة اليسارية دائماً في “نهاية” السلسلة الزمنية بعدد $k-1$ مشاهدة؛ نظراً لعدم توفر بيانات مستقبلية كافية بعد النقطة $N – k + 1$. يُستخدم هذا النمط على سبيل المثال عند الرغبة في اختبار فرضية تقيس ما إذا كان اتخاذ قرار تسويقي أو طبي معين في اليوم $t$ يرتبط إحصائياً بارتفاع متوسط الأداء في الأيام الثلاثة التالية لذلك القرار مباشرة.

# مقارنة برمجية شاملة لكافة أنماط المحاذاة لنفس النافذة (k = 3)
df_alignment_comparison <- df %>%
 dplyr::mutate(
 right_avg = zoo::rollmean(sales, k = 3, fill = NA, align = "right"),
 center_avg = zoo::rollmean(sales, k = 3, fill = NA, align = "center"),
 left_avg = zoo::rollmean(sales, k = 3, fill = NA, align = "left")
 )
# طباعة جدول المقارنة لتوضيح تموضع قيم NA والقيم المحسوبة
print(df_alignment_comparison)

8. إدارة القيم المفقودة ومعالجة أطراف السلاسل الزمنية

8.1 التعامل مع قيم NA الموجودة مسبقاً في البيانات

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

للتعامل مع هذا التحدي، يمكن تمرير المعامل na.rm = TRUE داخل الدالة لتوجيه المحرك الحسابي لاستبعاد القيم المفقودة وحساب المتوسط على المشاهدات المتوفرة فقط داخل النافذة. ومع ذلك، يجب الحذر المنهجي من أن استخدام na.rm = TRUE يؤدي ضمنياً إلى تغيير حجم النافذة الفعلي الفعال ($k_{\text{effective}}$) بين نقطة وأخرى؛ فإذا كانت النافذة بطول 5 وتحتوي على قيمتين مفقودتين، سيتم الحساب بالقسمة على 3 مشاهدات فقط، مما يزيد من تباين المقدر عند تلك النقاط.

في البيئات التحليلية المتقدمة، يُفضل دائماً معالجة الفجوات المفقودة مسبقاً قبل تطبيق التنعيم باستخدام تقنيات “الاستكمال الداخلي للبيانات” (Data Imputation) مثل الاستكمال الخطي (Linear Interpolation) أو استكمال الشرائح الميمونة (Spline Interpolation) المتوفرة في حزمة zoo عبر دالتي na.approx() و na.spline()، مما يحافظ على التوزيع الزمني المنتظم للسلسلة قبل تنعيمها.

8.2 التحكم في معالجة حدود السلسلة (Boundary Constraints)

يشكل فقدان البيانات عند حواف السلسلة الزمنية (ظهور $k-1$ من قيم NA) عائقاً في بعض التطبيقات العملية التي تتطلب الحصول على قيمة ممهدة لكل نقطة زمنية دون استثناء. لتجاوز هذا القيد، يمكن اللجوء إلى تقنيات “النوافذ التكيفية عند الحواف” (Adaptive Windowing) أو استخدام دوال مخصصة تتوسع تدريجياً عند البدايات.

توفر حزمة zoo الدالة العامة فائقة المرونة rollapply()، بالإضافة إلى الاختصار المباشر rollmeanr() (الذي يمثل اختصاراً مدمجاً لـ rollmean(..., align = "right")). من خلال استخدام rollapply() مع تمرير دالة متوسط مخصصة تضبط معامل partial = TRUE، يمكن توجيه R لحساب المتوسط للنوافذ الجزئية غير المكتملة عند الحواف؛ بحيث يُحسب الصف الأول كمتوسط لنفسه فقط، والصف الثاني كمتوسط للنقطتين الأولى والثانية، وهكذا حتى تكتمل النافذة بالحجم $k$:

# حساب المتوسط المتحرك التكيفي عند الحواف باستخدام rollapply
df_adaptive <- df %>%
 dplyr::mutate(
 # partial = TRUE تضمن عدم فقدان أي صف عند البداية
 adaptive_avg = zoo::rollapply(
 data = sales, 
 width = 3, 
 FUN = mean, 
 na.rm = TRUE, 
 fill = NA, 
 align = "right", 
 partial = TRUE
 )
 )
# استعراض النتائج والتأكد من اختفاء قيم NA عند البدايات
print(df_adaptive)

توفر هذه الاستراتيجية حلاً هندسياً ممتازاً للأنظمة التحليلية التي تفرض قيوداً تقنية صارمة تمنع وجود أي قيم مفقودة في المخرجات الجداولية النهائية.

9. مقارنة سلوك النوافذ الزمنية المتعددة (Multi-Window Analysis)

9.1 حساب نوافذ متعددة في جدول واحد (3، 5، و7 أيام)

في التحليلات المتقدمة للسلاسل الزمنية، لا يكتفي الباحثون بفحص نافذة زمنية مفردة، بل يُعتمد منهج “التحليل متعدد النطاقات الزمنية” (Multi-Scale Temporal Analysis) لمقارنة التفاعلات بين الديناميكيات قصيرة الأجل وطويلة الأجل بالتوازي. يتيح لنا خط أنابيب dplyr حساب عدة مؤشرات متحركة لنوافذ مختلفة الاتساع ($k=3, k=5, k=7$) بأسلوب برمجي موحد وعالي الكفاءة:

# حساب متوسطات متحركة متعددة النوافذ بالتوازي
df_multi_window <- df %>%
 dplyr::mutate(
 roll_3 = zoo::rollmean(sales, k = 3, fill = NA, align = "right"),
 roll_5 = zoo::rollmean(sales, k = 5, fill = NA, align = "right"),
 roll_7 = zoo::rollmean(sales, k = 7, fill = NA, align = "right")
 )
# طباعة الجدول المقارن الموسع
print(df_multi_window)

يُظهر الجدول الناتج تناقصاً تدريجياً في عدد القيم المحسوبة الفعالة مع زيادة حجم النافذة؛ حيث يتطلب مؤشر roll_3 فقدان صفين عند البداية، بينما يتطلب مؤشر roll_5 فقدان 4 صفوف، ويتطلب roll_7 فقدان 6 صفوف كاملة. كما يُلاحظ إحصائياً انخفاض تباين القيم وتناقص انحرافها المعياري الموضعي كلما اتسعت النافذة، وفقاً للمبدأ الرياضي القائل بأن تباين متوسط $k$ من المتغيرات العشوائية المستقلة يتناسب عكسياً مع حجم العينة ($\sigma^2_{\bar{x}} = \frac{\sigma^2}{k}$).

9.2 دراسة التفاعل بين حساسية التغير ومستوى التنعيم

يكشف التحليل المقارن للنوافذ الزمنية المتعددة عن الفروق السلوكية الدقيقة لكل مقياس:

النافذة القصيرة ($k=3$): تتسم بحساسية واستجابة فائقة السرعة للتغيرات الصاعدة والهابطة في السلسلة الزمنية. يُلاحظ أنها تلتقط الهبوط المؤقت في اليوم الرابع (انخفاض المبيعات إلى 14) بانخفاض فوري في المتوسط المتحرك. ميزتها هي سرعة التحذير من التغيرات المفاجئة، وعيبها هو استمرار احتوائها على تذبذبات خشنة قد تضلل المراقب.

النافذة المتوسطة ($k=5$): تمثل حلاً وسطاً متزناً؛ حيث تمتص الهبوط اللحظي لليوم الرابع جزئياً دون أن تعكسه كانخفاض حاد، مما يوفر خط اتجاه وسيط يعبر عن التوجه الأسبوعي المصغر دون تأخر زمني مفرط.

النافذة الطويلة ($k=7$): تنتج مساراً فائق النعومة والتجانس يعزل الاتجاه الصعودي العام للبيانات متجاهلاً كافة المطبات اللحظية. ومع ذلك، يتضح التأخر الزمني الكبير في هذه النافذة؛ حيث لا تبدأ في إعطاء قيم إلا عند اليوم السابع، وتكون قيمتها التقديرية متأخرة عن المستويات السعرية أو البيعية الحالية بنحو 3 إلى 4 أيام، مما يجعلها أداة لتأكيد الاتجاهات طويلة الأجل وليست أداة لاقتناص اللحظات الآنية.

10. طرق وحزم بديلة لحساب المتوسط المتحرك في R

10.1 استخدام حزمة slider لحسابات النوافذ المتقدمة

تمثل حزمة slider أحدث ثورة برمجية في منظومة Tidyverse للتعامل مع العمليات الانزلاقية عبر السلاسل الزمنية. تم تصميم حزمة slider للتغلب على كافة القيود التاريخية لحزم السلاسل الزمنية الكلاسيكية، وتوفير واجهة موحدة تتكامل تكاملاً تاماً مع أدوات مثل tibble و purrr.

توفر الدالة slide_dbl() تحكماً غير مسبوق في هندسة النافذة عبر المعاملين .before و .after. بدلاً من الاعتماد على مصطلحات المحاذاة التقليدية، تتيح slider للمحلل تحديد عدد الفترات المطلوبة بدقة متناهية قبل النقطة الحالية وبعدها، بالإضافة إلى دعم النوافذ التقويمية القائمة على التواريخ الفعلية (مثل نافذة شهر كامل بغض النظر عن عدد أيام العطلات داخله):

# استدعاء مكتبة slider الحديثة
# install.packages("slider")
library(slider)
# حساب المتوسط المتحرك لـ 3 أيام (المشاهدة الحالية + نقطتان سابقتان)
df_slider <- df %>%
 dplyr::mutate(
 slider_avg = slider::slide_dbl(
 .x = sales, 
 .f = mean, 
 .before = 2, 
 .after = 0, 
 .complete = TRUE
 )
 )
# طباعة مخرجات slider
print(df_slider)

يضمن ضبط المعامل .complete = TRUE الحفاظ على البنية الصارمة للنوافذ الكاملة وإرجاع NA عند عدم اكتمال النافذة، تماماً كما تفعل دالة rollmean()، ولكن بصياغة برمجية أكثر مرونة وقابلية للتوسع لتشمل شروطاً زمنية شديدة التعقيد.

10.2 استخدام حزمة data.table للبيانات الضخمة (Big Data)

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

تقدم حزمة data.table الدالة المتخصصة فائقة السرعة frollmean() (Fast Rolling Mean)، والمكتوبة بلغة C المحسنة إلى أقصى الحدود، والتي تستهلك جزءاً ضئيلاً جداً من الذاكرة مقارنة ببقية الحزم:

# استدعاء مكتبة data.table
# install.packages("data.table")
library(data.table)
# تحويل جدول البيانات إلى كائن data.table فائق السرعة
dt <- as.data.table(df)
# حساب المتوسط المتحرك السريع عبر التعديل الموضعي في الذاكرة (In-place modification)
dt[, froll_avg := frollmean(sales, n = 3, align = "right", fill = NA)]
# عرض محتوى data.table
print(dt)

يتميز استخدام المشغل الموضعي := في data.table بتعديل الجدول في مكانه داخل الذاكرة دون إنشاء نسخ إضافية، مما يجعلها الخيار الإلزامي في البيئات الإنتاجية ذات المتطلبات الحسابية العالية وزمن التنفيذ الحرج.

10.3 استخدام دالة rollapply() العامة للعمليات الحسابية المخصصة

لا تتوقف التحليلات الإحصائية عند حدود المتوسط الحسابي؛ ففي كثير من الأحيان يحتاج المحلل إلى حساب مقاييس إحصائية متحركة أخرى لفهم تغيرات التشتت والاستقرار، مثل “الانحراف المعياري المتحرك” (Rolling Standard Deviation) لتقييم تقلبات المخاطر، أو “الوسيط المتحرك” (Rolling Median) لتوفير مقياس فائق المناعة ضد القيم الشاذة والمتطرفة.

تُعد دالة zoo::rollapply() الإطار البرمجي الأوسع لتطبيق أي دالة إحصائية قياسية أو مخصصة عبر نافذة متحركة:

# حساب الوسيط المتحرك والانحراف المعياري المتحرك عبر rollapply
df_custom_stats <- df %>%
 dplyr::mutate(
 # الوسيط المتحرك لـ 3 أيام
 roll_median = zoo::rollapply(sales, width = 3, FUN = median, fill = NA, align = "right"),
 # الانحراف المعياري المتحرك لـ 3 أيام (مقياس التذبذب)
 roll_sd = zoo::rollapply(sales, width = 3, FUN = sd, fill = NA, align = "right")
 )
# عرض المؤشرات المركبة
print(df_custom_stats)

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

11. التصور البياني للمتوسطات المتحركة باستخدام ggplot2

11.1 رسم البيانات الأصلية مع خطوط التنعيم المتحركة

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

نقوم أولاً بتحضير البيانات وحساب المتوسطات المتحركة لثلاثة أيام وخمسة أيام، ثم نبني طبقات الرسم البياني تدريجياً عبر إضافة الخطوط (geom_line) والنقاط التجريبية (geom_point) مع تخصيص الألوان وسمك الخطوط:

# استدعاء مكتبة ggplot2
library(ggplot2)
# تجهيز البيانات بمتوسطات متحركة متعددة
plot_data <- df %>%
 dplyr::mutate(
 SMA_3 = zoo::rollmean(sales, k = 3, fill = NA, align = "right"),
 SMA_5 = zoo::rollmean(sales, k = 5, fill = NA, align = "right")
 )
# بناء المخطط البياني التراكمي
p <- ggplot(data = plot_data, aes(x = day)) +
 # رسم السلسلة الأصلية بخط رمادي متقطع ونقاط بارزة
 geom_line(aes(y = sales, color = "البيانات الأصلية"), linetype = "dashed", size = 0.8) +
 geom_point(aes(y = sales, color = "البيانات الأصلية"), size = 2.5) +
 # رسم المتوسط المتحرك لـ 3 أيام بخط أزرق متصل
 geom_line(aes(y = SMA_3, color = "متوسط متحرك (3 أيام)"), size = 1.2) +
 # رسم المتوسط المتحرك لـ 5 أيام بخط أحمر متصل
 geom_line(aes(y = SMA_5, color = "متوسط متحرك (5 أيام)"), size = 1.2)
# استعراض المخطط الأولي
print(p)

11.2 بناء وسيلة إيضاح احترافية وتنسيق المخطط

لتحويل المخطط البياني إلى مخرج بصري احترافي صالح للنشر الأكاديمي والتقارير التنفيذية، نقوم بإعادة هيكلة البيانات اختيارياً إلى النسق الطولي (Long Format) عبر tidyr::pivot_longer() أو تخصيص لوحة الألوان والسمات البصرية مباشرة باستخدام دوال التحكم في السمات theme_minimal() وتخصيص العناوين والمحاور:

# تحسين المظهر الجمالي وتنسيق عناصر المخطط النهائي
final_plot <- p +
 scale_color_manual(
 name = "دليل المؤشرات الإحصائية:",
 values = c(
 "البيانات الأصلية" = "#7f8c8d",
 "متوسط متحرك (3 أيام)" = "#2980b9",
 "متوسط متحرك (5 أيام)" = "#e74c3c"
 )
 ) +
 scale_x_continuous(breaks = 1:10) +
 scale_y_continuous(breaks = seq(10, 30, by = 2)) +
 labs(
 title = "التحليل البصري لتنعيم السلاسل الزمنية باستخدام المتوسطات المتحركة",
 subtitle = "مقارنة السلوك التمهيدي لنافذة 3 أيام و 5 أيام مقابل مبيعات 10 أيام متتالية",
 x = "المشاهدة الزمنية (اليوم)",
 y = "حجم المبيعات (وحدة)",
 caption = "المصدر: حسابات تجريبية مبرمجة بلغة R باستخدام حزمة zoo و ggplot2"
 ) +
 theme_minimal(base_size = 13) +
 theme(
 plot.title = element_text(face = "bold", hjust = 0.5, size = 15, margin = margin(b = 8)),
 plot.subtitle = element_text(hjust = 0.5, size = 11, margin = margin(b = 15)),
 plot.caption = element_text(hjust = 0, size = 9, color = "#7f8c8d", margin = margin(t = 10)),
 legend.position = "bottom",
 legend.title = element_text(face = "bold"),
 legend.background = element_rect(fill = "#f8f9fa", color = "#dcdde1"),
 panel.grid.minor = element_blank(),
 panel.grid.major = element_line(color = "#ecf0f1")
 )
# طباعة وحفظ المخطط البياني النهائي
print(final_plot)

يُظهر المخطط البياني النهائي بوضوح شديد ظاهرة “تخفيف القمم والقيعان”؛ حيث يقطع خط المتوسط المتحرك لـ 3 أيام التعرجات الحادة للسلسلة الأصلية بسلاسة، بينما يظهر خط المتوسط لـ 5 أيام كمنحنى أكثر تسطيحاً واستقراراً يوضح الاتجاه الصعودي العام للنمو التراكمي للمبيعات، متجاوزاً كافة التموجات قصيرة الأجل.

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

12.1 الأخطاء الشائعة في حساب المتوسط المتحرك وكيفية تفاديها

يقع العديد من الممارسين ومحللي البيانات المبتدئين في أخطاء منهجية وبرمجية متكررة عند حساب المتوسطات المتحركة، نلخص أبرزها وكيفية تجنبها:

  • خطأ عدم فرز البيانات زمنياً: تفترض دوال النوافذ المتحركة مثل rollmean() ضمنياً أن البيانات مرتبة ترتيباً زمنياً تصاعدياً دقيقاً. إذا كانت البيانات غير مرتبة مسبقاً (بسبب عمليات دمج أو تجميع سابقة)، فإن الدالة ستحسب المتوسطات عبر صفوف متجاورة لا تمثل فترات زمنية متتالية، مما يدمر الصلاحية العلمية للنتائج بالكامل. يُلزم دائماً تطبيق dplyr::arrange(Date) قبل الشروع في حساب المتوسطات.
  • الحذف العشوائي لصفوف NA الأولية: يؤدي استخدام دوال التخلص التلقائي من القيم المفقودة مثل na.omit() أو tidyr::drop_na() دون وعي إلى حذف الصفوف الأولى من مجموعة البيانات بأكملها (وليس فقط من عمود المتوسط)، مما يتسبب في فقدان المشاهدات الأصلية لتلك الأيام وحرمان بقية النماذج من بياناتها الأساسية.
  • الخلط الكارثي بين المحاذاة اليمينية والمركزية في النماذج التنبؤية: تطبيق align = "center" في مشروعات التنبؤ الآلي يؤدي إلى تسريب معلومات الغد إلى نموذج اليوم، مما يجعل التقييم النظري للنموذج خادعاً وفاشلاً تماماً في البيئة الإنتاجية الحية.
  • تجاهل الفروق في التباعد الزمني: تطبيق النوافذ بناءً على عدد الصفوف ($k$) يفترض تباعداً زمنياً متساوياً بين الصفوف. إذا كانت السلسلة تحتوي على أيام مفقودة (مثل عطلات نهاية الأسبوع)، فإن النافذة ذات الـ 7 صفوف قد تمتد فعلياً عبر 10 أو 11 يوماً، مما يقتضي إعادة هيكلة السلسلة لتشمل كافة التواريخ وتعبئة الفجوات قبل الحساب، أو استخدام حزم قائمة على الفترات الزمنية الفعلية مثل slider.

12.2 معايير الجودة والتوثيق الأكاديمي للتحليلات الزمنية

لضمان الارتقاء بالتحليلات الإحصائية للسلاسل الزمنية إلى المعايير الأكاديمية والمهنية الصارمة، يجب على الباحثين ومحللي البيانات الالتزام بعدد من الإجراءات المنهجية التوثيقية:

أولاً، يجب التوثيق الصريح لحجم نافذة المراقبة ($k$) وتقديم المبررات الإحصائية والفيزيائية لاختيار هذا الحجم؛ كأن يتم توضيح أن $k=7$ استُخدمت لامتصاص الدورة الأسبوعية، أو أن $k=12$ استُخدمت لمعادلة النمط الموسمي الشهري في البيانات السنوية. كما يجب توثيق نوع المحاذاة الهندسية المتبعة (align) والأسلوب المعتمد لإدارة حواف السلسلة والقيم المفقودة.

ثانياً، يجب توفير الأكواد البرمجية بصيغة قابلة لإعادة الإنتاج التام (Reproducible Workflow)، متضمنة تحديد إصدارات الحزم المستخدمة (عبر sessionInfo()) وتثبيت البذور العشوائية (set.seed) في حال تضمنت المعالجة أي عمليات توليد عشوائي أو استكمال احتمالي للبيانات.

ثالثاً، يجب إجراء تقييم نقدي لمدى كفاية المتوسط المتحرك كأداة وحيدة؛ فالمتوسط المتحرك هو في جوهره “مرشح خطي غير حدودي” (Non-parametric Linear Filter)، وقد لا يكون كافياً بذاته عند الرغبة في إجراء تنبؤات استشرافية احتمالية ذات فترات ثقة إحصائية دقيقة. في مثل هذه الحالات، يجب الإشارة إلى ضرورة الانتقال إلى النماذج الإحصائية القياسية المتقدمة مثل نماذج الانحدار الذاتي والمتوسطات المتحركة التكاملية (ARIMA)، ونماذج التمهيد الأسي لحالة الفضاء (ETS)، ونماذج الفضاء الخطي المتغيرة عبر الزمن (State-Space Models)، والتي تبني على هذه المفاهيم وتوفر إطاراً تنبؤياً احتمالياً متكاملاً.

خاتمة

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

References

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

looti, M. (2026, سبتمبر 1). كيفية حساب المتوسط المتحرك في R (مع مثال). عرب سايكلوجي. https://arabpsychology.com/how-to-calculate-rolling-average-in-r/
looti, Mohammed. “كيفية حساب المتوسط المتحرك في R (مع مثال).” عرب سايكلوجي, 1 سبتمبر 2026, https://arabpsychology.com/how-to-calculate-rolling-average-in-r/.
looti, Mohammed. “كيفية حساب المتوسط المتحرك في R (مع مثال).” عرب سايكلوجي. سبتمبر 1, 2026. https://arabpsychology.com/how-to-calculate-rolling-average-in-r/.