Pandas: دوال النوافذ
آخر تحديث: 2026-08-26
الدرس 17 قدّم الدوال rolling/expanding/ewm. يتعمّق هذا الدرس أكثر: التجميع بنوافذ مخصّصة، ونوافذ الوقت المتقدمة، وعلاقات معاملات ewm، وتركيبات groupby مع rolling. الدوال النافذة هي أداة أساسية في التحليل الكمي ومعالجة بيانات الاستشعار — تعلّمها جيداً يعني تعلّم القدرة على "رؤية الاتجاهات من خلال عدسة منزلقة."
1. What You Will Learn
- ❶ Advanced rolling parameters
- ❷ Custom window aggregation
- ❸ expanding cumulative windows in depth
- ❹ ewm parameters explained
- ❺ groupby + rolling
2. تحليل نافذة معدل نبضات قلب كارول أثناء التمرين
(3) المشكلة (1): متوسط النافذة لمدة 30 ثانية ليس كافيًا
تحتاج بيانات معدل نبضات قلب كارول أثناء التمرين إلى إحصائيات نافذة أكثر تفصيلاً — ليس المتوسط فقط، بل أيضًا الحد الأقصى وتنوع معدل ضربات القلب (الانحراف المعياري):
import pandas as pd
import numpy as np
np.random.seed(42)
hr = pd.DataFrame({
'heart_rate': np.random.normal(75, 10, 60).round(0)
}, index=pd.date_range('2024-01-15 08:00', periods=60, freq='30s'))
> **الإخراج:** قم بالتشغيل في بيئة بايثون المحلية الخاصة بك (pandas 2.x). خادم Piston لا يحتوي على مكتبة pandas مثبتة مسبقاً. يرجى تثبيتها محلياً (`pip install pandas`) والمتابعة. قد تختلف القيم الفعلية قليلاً حسب إصدار pandas.
(4) الحل (2): rolling مع عمليات تجميع متعددة
▶ مثال: إحصائيات متعددة المعايير للدوال المتحركة (الصعوبة ⭐)
import pandas as pd
import numpy as np
np.random.seed(42)
hr = pd.DataFrame({
'heart_rate': np.random.normal(75, 10, 60).round(0)
}, index=pd.date_range('2024-01-15 08:00', periods=60, freq='30s'))
# الدوال المتحركة مع عمليات تجميع متعددة
stats = hr['heart_rate'].rolling(10).agg(['mean', 'std', 'min', 'max'])
stats.columns = ['hr_ma', 'hr_std', 'hr_min', 'hr_max']
print(stats.dropna().head(5).round(1))
> **الإخراج:** قم بالتشغيل في بيئة بايثون المحلية الخاصة بك (pandas 2.x). خادم Piston لا يحتوي على مكتبة pandas مثبتة مسبقاً. يرجى تثبيتها محلياً (`pip install pandas`) والمتابعة. قد تختلف القيم الفعلية قليلاً حسب إصدار pandas.
3. المتقدمة للأسطوانات
(1) المعاملات الرئيسية
▶ مثال
> **Output:** Run in your local Python environment (pandas 2.x). The Piston server does not have pandas pre-installed. Please install it locally (`pip install pandas`) and follow along. Actual values may vary slightly depending on the pandas version.
: مرجع معاملات الأسطوانات (الصعوبة ⭐⭐)
import pandas as pd
import numpy as np
np.random.seed(42)
s = pd.Series(np.random.randn(20).cumsum() + 100)
# min_periods: allow partial windows
print(s.rolling(5, min_periods=2).mean().head(5))
# center: centered window (for smoothing)
print(s.rolling(5, center=True).mean().head(5))
# win_type: weighted window (Gaussian, triangular, etc.)
print(s.rolling(5, win_type='gaussian').mean(std=1.5).head(8))
# on: use a column as time (when not the index)
df = pd.DataFrame({
'timestamp': pd.date_range('2024-01', periods=20, freq='6h'),
'value': np.random.randn(20).cumsum()
})
print(df.rolling('12h', on='timestamp')['value'].mean().head(5))
> **Output:** Run in your local Python environment (pandas 2.x). The Piston server does not have pandas pre-installed. Please install it locally (`pip install pandas`) and follow along. Actual values may vary slightly depending on the pandas version.
(2) مرجع سريع لمعاملات الأسطوانات
| المعامل | الافتراضي | الوصف |
|---|---|---|
| window | مطلوب | حجم النافذة (عدد صحيح من الصفوف أو سلسلة زمنية) |
| min_periods | window | الحد الأدنى من الملاحظات المطلوبة في النافذة |
| center | False | تمركز النافذة |
| win_type | None | نوع الترجيح (gaussian/triangular، إلخ) |
| on | None | استخدام عمود كمحور زمني (بدلاً من الفهرس) |
| closed | 'right' | أي طرف من النافذة يكون متضمنًا |
4. تجميع النافذة المخصصة
▶ مثال
> **Output:** Run in your local Python environment (pandas 2.x). The Piston server does not have pandas pre-installed. Please install it locally (`pip install pandas`) and follow along. Actual values may vary slightly depending on the pandas version.
: دوال التجميع المخصصة (الصعوبة ⭐⭐⭐)
import pandas as pd
import numpy as np
np.random.seed(42)
df = pd.DataFrame({
'value': np.random.randint(10, 100, 20)
})
# Custom: range (max - min) in window
def window_range(arr):
return arr.max() - arr.min()
df['rolling_range'] = df['value'].rolling(5).apply(window_range, raw=True)
# Custom: coefficient of variation (std/mean)
def cv(arr):
return arr.std() / arr.mean() if arr.mean() != 0 else 0
df['rolling_cv'] = df['value'].rolling(5).apply(cv, raw=True)
# Using rolling.apply with raw=True for performance
# raw=True: receives numpy array (fast)
# raw=False: receives Series (slow but flexible)
print(df.head(10))
> **Output:** Run in your local Python environment (pandas 2.x). The Piston server does not have pandas pre-installed. Please install it locally (`pip install pandas`) and follow along. Actual values may vary slightly depending on the pandas version.
raw=True في الدوال المخصصة أسرع بحوالي 10 مرات (يستقبل مصفوفة NumPy بدلاً من Series)، لكنك تفقد الوصول إلى معلومات الفهرس. استخدم raw=True للحسابات الرقمية البسيطة؛ استخدم raw=False عندما تحتاج إلى الفهرس.
5. التوسع بالتفصيل
▶ مثال
> **الإخراج:** قم بالتشغيل في بيئة Python المحلية الخاصة بك (pandas 2.x). خادم Piston لا يحتوي على pandas مثبّتًا مسبقًا. يرجى تثبيته محليًا (`pip install pandas`) والمتابعة. قد تختلف القيم الفعليّة قليلاً حسب إصدار pandas.
: دوال توسع مخصّصة (الصعوبة ⭐)
import pandas as pd
import numpy as np
np.random.seed(42)
df = pd.DataFrame({
'score': np.random.randint(60, 100, 15)
})
# Built-in expanding methods
df['cummean'] = df['score'].expanding().mean()
df['cumstd'] = df['score'].expanding().std()
df['cummax'] = df['score'].expanding().max()
# Expanding with min_periods
df['cummean_5'] = df['score'].expanding(min_periods=5).mean()
# Custom: expanding z-score
def zscore(arr):
if len(arr) < 2: return np.nan
return (arr[-1] - arr.mean()) / arr.std()
df['zscore'] = df['score'].expanding().apply(zscore, raw=True)
print(df.round(2).head(10))
> **الإخراج:** قم بالتشغيل في بيئة Python المحلية الخاصة بك (pandas 2.x). خادم Piston لا يحتوي على pandas مثبّتًا مسبقًا. يرجى تثبيته محليًا (`pip install pandas`) والمتابعة. قد تختلف القيم الفعليّة قليلاً حسب إصدار pandas.
6. توضيحات معاملات ewm
(1) العلاقات بين المعاملات الأربعة
| المعامل | العلاقة | المعنى |
|---|---|---|
| span | com = span - 1 | مشابه لمتوسط SMA لـ N فترة |
| com | α = 1/(1+com) | مركز الكتلة |
| halflife | α = 1 - 0.5^(1/halflife) | عدد الفترات لتصبح الوزن نصفها |
| alpha | يحدد مباشرة | معامل التنعيم 0<α≤1 |
▶ مثال
> **الإخراج:** قم بالتشغيل في بيئة Python المحلية (pandas 2.x). خادم Piston لا يحتوي على pandas مثبته مسبقاً. يرجى تثبيته محليًا (`pip install pandas`) واتباع الشروحات. قد تختلف القيم الفعلي قليلاً اعتماداً على إصدار pandas.
: مقارنة معاملات ewm (الصعوبة ⭐⭐)
import pandas as pd
import numpy as np
np.random.seed(42)
s = pd.Series(np.random.randn(30).cumsum() + 100)
# هذه جميعها متكافئة (تقريبيًا)
ewm_span5 = s.ewm(span=5).mean()
ewm_com4 = s.ewm(com=4).mean() # com = span - 1
ewm_hl3 = s.ewm(halflife=3).mean() # وزن مختلف
ewm_alpha = s.ewm(alpha=0.333).mean() # alpha = 2/(span+1)
# مقارنة مع SMA
sma5 = s.rolling(5).mean()
print("SMA مقارنة مع EWM (أول 10 قيم):")
print(pd.DataFrame({
'القيمة': s, 'SMA_5': sma5, 'EWM_span5': ewm_span5
}).head(10).round(2))
# الانحراف المعياري ewm (التقلب)
ewm_std = s.ewm(span=10).std()
print(f"\nآخر انحراف معياري لـ EWM: {ewm_std.iloc[-1]:.2f}")
> **الإخراج:** قم بالتشغيل في بيئة Python المحلية (pandas 2.x). خادم Piston لا يحتوي على pandas مثبته مسبقاً. يرجى تثبيته محليًا (`pip install pandas`) واتباع الشروحات. قد تختلف القيم الفعلي قليلاً اعتماداً على إصدار pandas.
7. تجميع مع النوافذ المتحركة (groupby + rolling)
▶ مثال
> **الخرج:** قم بالتشغيل في بيئة بايثون المحلية الخاصة بك (pandas 2.x). خادم Piston لا يحتوي على مكتبة pandas مثبتة مسبقًا. يرجى تثبيتها محليًا (`pip install pandas`) والعمل مع الشروحات. قد تختلف القيم الفعلية قليلاً اعتماداً على إصدار المكتبة.
: النوافذ المتحركة داخل المجموعات (الصعوبة ⭐⭐⭐)
import pandas as pd
import numpy as np
# بيانات المستشعرات: مستشعرات متعددة، لكل منها سلسلة زمنية خاصة به
np.random.seed(42)
df = pd.DataFrame({
'sensor_id': np.repeat(['T01', 'T02', 'T03'], 20),
'timestamp': list(pd.date_range('2024-01', periods=20, freq='6h')) * 3,
'temperature': np.random.normal(20, 3, 60).round(1)
})
# التدوير داخل كل مجموعة مستشعرات
df = df.sort_values(['sensor_id', 'timestamp'])
df['temp_ma'] = df.groupby('sensor_id')['temperature'].transform(
lambda x: x.rolling(4, min_periods=1).mean()
)
# بديل: groupby + rolling (يعيد مؤشرًا متعدد المستويات)
result = df.groupby('sensor_id')['temperature'].rolling(4).mean()
print(result.head(12))
# إعادة الضبط للحصول على خرج نظيف
df['temp_ma2'] = df.groupby('sensor_id')['temperature'].transform(
lambda x: x.rolling(4).mean().values
)
print(df[df['sensor_id'] == 'T01'].head(6))
> **الخرج:** قم بالتشغيل في بيئة بايثون المحلية الخاصة بك (pandas 2.x). خادم Piston لا يحتوي على مكتبة pandas مثبتة مسبقًا. يرجى تثبيتها محليًا (`pip install pandas`) والعمل مع الشروحات. قد تختلف القيم الفعلية قليلاً اعتماداً على إصدار المكتبة.
8. مثال كامل: تحليل بيانات معدل ضربات القلب أثناء التمرين
(5) ▶ مقارنة ثلاثة أنواع من النوافذ
graph LR
A[Window Functions] --> B[rolling Fixed Window]
A --> C[expanding Cumulative Window]
A --> D[ewm Exponential Weighting]
B --> E[Local Trends / Moving Average]
C --> F[Cumulative Stats / From Start to Now]
D --> G[Recent Data Weighted More / Smoothing]
> **Output:** Run in your local Python environment (pandas 2.x). The Piston server does not have pandas pre-installed. Please install it locally (`pip install pandas`) and follow along. Actual values may vary slightly depending on the pandas version.
▶ مثال
> **Output:** Run in your local Python environment (pandas 2.x). The Piston server does not have pandas pre-installed. Please install it locally (`pip install pandas`) and follow along. Actual values may vary slightly depending on the pandas version.
: خط تحليل النوافذ الكامل (الصعوبة ⭐⭐⭐)
import pandas as pd
import numpy as np
# ============================================
# مثال شامل: اللياقة البدنية معدل ضربات القلب
# خط تحليل النوافذ
# ============================================
# 1. إنشاء بيانات تمرين لمدة ساعتين (قراءة واحدة كل 30 ثانية = 240 صفًا)
np.random.seed(42)
timestamps = pd.date_range('2024-01-15 08:00', periods=240, freq='30s')
exercise_type = (['Warmup'] * 30 + ['Cardio'] * 90 + ['Weights'] * 60 + ['Cooldown'] * 60)
hr_base = ([70] * 30 + list(np.linspace(70, 140, 90)) + [120] * 60 + list(np.linspace(120, 70, 60)))
heart_rates = [max(50, h + np.random.randn() * 5) for h in hr_base]
df = pd.DataFrame({
'timestamp': timestamps,
'exercise': exercise_type,
'heart_rate': np.round(heart_rates, 0)
})
# 2. متوسط متحرك متنقل: 1 دقيقة (2 قراءة) و 5 دقائق (10 قراءات)
df['hr_ma_1min'] = df['heart_rate'].rolling(2).mean()
df['hr_ma_5min'] = df['heart_rate'].rolling(10).mean()
# 3. متوسط متحرك متنقل: تباين معدل ضربات القلب (الانحراف المعياري في نافذة 5 دقائق)
df['hrv'] = df['heart_rate'].rolling(10).std()
# 4. متوسط متحرك متوسع: المتوسط التراكمي
df['cum_avg_hr'] = df['heart_rate'].expanding().mean()
# 5. المتوسط المتحرك الأسّي: اتجاه مُنعم
df['hr_ewm'] = df['heart_rate'].ewm(span=10).mean()
# 6. تجميع + متوسط متحرك متنقل: لكل نوع تمرين
df['hr_ma_per_exercise'] = df.groupby('exercise')['heart_rate'].transform(
lambda x: x.rolling(5, min_periods=1).mean()
)
# 7. ملخص حسب التمرين
print("=== ملخص التمرين ===")
summary = df.groupby('exercise')['heart_rate'].agg(['mean', 'max', 'min', 'std']).round(1)
print(summary)
> **Output:** Run in your local Python environment (pandas 2.x). The Piston server does not have pandas pre-installed. Please install it locally (`pip install pandas`) and follow along. Actual values may vary slightly depending on the pandas version.
❓ أسئلة شائعة
rolling('7D') يستخدم نافذة تقويمية مدتها 7 أيام، بينما rolling(7) يستخدم نافذة مكونة من 7 صفوف. النوافذ المبنية على الوقت مثالية للبيانات المأخوذة بعينات غير منتظمة (مع تخطي عطل نهاية الأسبوع أو الأيام المفقودة)، بينما النوافذ المبنية على الصفوف تناسب أخذ العينات المنتظمة. تتطلب النوافذ المبنية على الوقت أن يكون الفهرس هو DatetimeIndex، أو يمكنك تحديد عمود الوقت باستخدام معامل on.pip install scipy. win_type يطبق أوزاناً على البيانات داخل النافذة (وزن أعلى في الوسط، وأقل على الحواف)، مما ينتج نتائج أكثر سلاسة من نافذة بوزن متساوٍ.📖 ملخص
- الدحرجة المتقدمة:
min_periodsيسمح بنوافذ جزئية،centerيركز النافذة،win_typeيطبق الترجيح،onيحدد عمود الوقت - التجميع المخصص يستخدم
.apply(func, raw=True)؛raw=Trueأسرع بحوالي 10 مرات expandingيتراكم من البداية إلى الوضع الحالي ويدعم أي دالة تجميع- معاملات
ewm:span(N فترات) /com(N-1) /halflife/alpha— جميعها متكافئة groupby+rolling: فرز أولاً، ثم الحساب؛transformيعيد نتيجة بنفس الطول- اختيار نوع النافذة: الاتجاهات المحلية →
rolling، التراكمي →expanding، التنعيم →ewm
📝 تمارين
- أساسي (مستوى الصعوبة ⭐): أنشئ بيانات درجة حرارة لمدة 30 يومًا. استخدم
rolling(7, min_periods=3)لحساب المتوسط المتحرك والانحراف المعياري، واستخدمewm(span=7)لحساب التنعيم الأسي. - متوسط (مستوى الصعوبة ⭐⭐): أنشئ بيانات درجة حرارة متعددة المستشعرات (3 مستشعرات، 20 صفًا لكل منها). استخدم
groupby+rollingلحساب المتوسط المتحرك لفترة 5 لكل مستشعر. - تحدي (مستوى الصعوبة ⭐⭐⭐): قم بمحاكاة 240 صفًا من بيانات معدل ضربات القلب أثناء التمارين (مع 4 أنواع تمارين). أكمل خط المعالجة التالي:
rollingمتعدد المقاييس (المتوسط/الانحراف المعياري/الأقصى) → المتوسط التراكمي المُوسَّع (expanding) → التنعيم الأسي (ewm) →groupby+rollingحسب نوع التمرين → تقرير ملخص.
← Previous Lesson: MultiIndex · Next Lesson: Visualization →