أساسيات pandas: السلاسل (Series) وإطارات البيانات (DataFrames) وفهرس التواريخ DatetimeIndex والتحديد والتصفية وإعادة تشكيل الشموع اليومية إلى أسبوعية
افهم Series وDataFrames، وفهرِس بيانات الأسعار بالتاريخ، وحدّد الصفوف باستخدام loc وiloc، وصفِّها بأقنعة منطقية، واجمع الشموع اليومية في شموع أسبوعية.
ما الذي ستتعلمه
- ما المقصود بـ
SeriesوDataFrame، ولماذا يُعدّDatetimeIndexالعمود الفقري لتحليل الأسعار. - الفرق بين
locالقائم على التسميات وilocالقائم على المواضع، وكيف تصفّي الأقنعة المنطقية الصفوف. - كيف تبني شموعًا أسبوعية أو شهرية من الشموع اليومية باستخدام
resampleمع طريقة التجميع الصحيحة لكل عمود. - أي الإعدادات الافتراضية في pandas تغيّرت في الإصدار 3.0، وكيف تكتب كودًا يتصرّف بالطريقة نفسها على 2.2 و3.x.
الشرح
السلسلة (Series) مصفوفة أحادية البعد ذات تسميات: عمود من أسعار الإغلاق يرتبط بكل قيمة فيه تاريخ. أما إطار البيانات (DataFrame) فهو جدول من السلاسل التي تتشارك فهرسًا واحدًا: الافتتاح والأعلى والأدنى والإغلاق والحجم جنبًا إلى جنب. يحمل الفهرس تسميات الصفوف؛ وفي بيانات الأسعار ينبغي أن يكون DatetimeIndex، وهو فهرس متخصص من الطوابع الزمنية يتيح التقطيع بالتاريخ وإعادة التشكيل والتعامل مع المناطق الزمنية. العُرف المتّبع: import pandas as pd.
أنشئ إطارًا من قاموس للأعمدة وفهرس للتواريخ:
idx = pd.bdate_range("2025-03-03", periods=10)
df = pd.DataFrame({"open": [...], "high": [...], "low": [...], "close": [...], "volume": [...]}, index=idx)
تُنتج bdate_range أيام العمل فقط ولا تعرف شيئًا عن عطلات البورصة؛ فالبيانات الحقيقية تأتي من الملفات (الدرس 4). افحص الإطار باستخدام df.head() وdf.info() (الأنواع والقيم المفقودة) وdf.describe(). يجب أن يُظهر df.index.dtype القيمة datetime64؛ فإذا أظهر object فهذا يعني أن التواريخ لا تزال نصًا.
التحديد. يعيد df["close"] سلسلة Series؛ ويعيد df[["open", "close"]] (قائمة) إطار DataFrame. يحدّد df.loc[row_labels, columns] حسب التسمية: يعطي df.loc["2025-03-05":"2025-03-07", "close"] أسعار الإغلاق لتلك التواريخ الثلاثة، ومع loc يُضمَّن طرفا الشريحة كلاهما، خلافًا لقوائم بايثون. أما df.iloc[0:3] فيحدّد حسب الموضع الرقمي (الصفوف الثلاثة الأولى، مع استبعاد النهاية)، وdf.iloc[-1] هو آخر شمعة.
التصفية. تُنتج المقارنة على سلسلة Series سلسلةً من القيم المنطقية تُسمّى قناعًا: up = df["close"] > df["open"]. وتمرير القناع يحدّد الصفوف المطابقة: df[up]. اجمع الأقنعة باستخدام & (و) و| (أو) و~ (ليس)، مع وضع كل شرط بين قوسين خاصين به: df[(df["close"] > df["open"]) & (df["volume"] > 1200)]. يعدّ up.sum() قيم True، وup.mean() هو نسبة الأيام الصاعدة.
إضافة الأعمدة تتم بالإسناد: df["range"] = df["high"] - df["low"]. العمليات متّجهة، أي تُطبَّق على أعمدة كاملة دفعة واحدة، ولهذا السبب يتسم pandas بالسرعة. ينقل shift(1) القيم صفًا واحدًا إلى الأسفل (إغلاق الأمس في صف اليوم)، ويعطي pct_change() التغيرات النسبية المئوية؛ وكلاهما يترك NaN (ليست رقمًا) في الصف الأول.
إعادة التشكيل. تجمّع resample الصفوف في فترات زمنية ثابتة. ويحتاج كل عمود إلى قاعدته الخاصة: الافتتاح الأسبوعي هو أول افتتاح يومي، والأعلى هو القيمة القصوى، والأدنى هو القيمة الدنيا، والإغلاق هو الأخير، والحجم هو المجموع:
rules = {"open": "first", "high": "max", "low": "min", "close": "last", "volume": "sum"}
weekly = df.resample("W-FRI").agg(rules)
الرمز "W-FRI" يسمّي كل أسبوع بيوم الجمعة فيه. وتستخدم الشموع الشهرية "ME" (نهاية الشهر). تكتب الدروس التعليمية القديمة "M"؛ وقد أوقف pandas 2.2 هذا الاسم المستعار لصالح "ME" (وكذلك "QE" و"YE")، والكود المكتوب بالأسماء المستعارة الجديدة يعمل على 2.2 و3.x كليهما.
تغييرات pandas 3.0 الجديرة بالمعرفة. أصبح النسخ عند الكتابة (Copy-on-Write) هو الوضع الوحيد: فالإطار المصفّى نسخة مستقلة، ولذلك لا يعدّل df[mask]["close"] = 0 الإطار df أبدًا؛ اكتب بدلًا من ذلك df.loc[mask, "close"] = 0. وصار نوع أعمدة النصوص str بدلًا من object.
مثال محلول
مثال افتراضي: عشر شموع يومية من الاثنين 3 مارس إلى الجمعة 14 مارس 2025، والأسعار باليورو، دون عطلات.
| التاريخ | الافتتاح | الأعلى | الأدنى | الإغلاق | الحجم |
|---|---|---|---|---|---|
| 03 مارس | 100 | 102 | 99 | 101 | 1,000 |
| 04 مارس | 101 | 104 | 100 | 103 | 1,200 |
| 05 مارس | 103 | 104 | 101 | 102 | 900 |
| 06 مارس | 102 | 105 | 101 | 104 | 1,100 |
| 07 مارس | 104 | 106 | 103 | 105 | 1,500 |
| 10 مارس | 105 | 106 | 103 | 104 | 1,300 |
| 11 مارس | 104 | 107 | 103 | 106 | 1,000 |
| 12 مارس | 106 | 108 | 105 | 107 | 1,400 |
| 13 مارس | 107 | 109 | 106 | 108 | 1,200 |
| 14 مارس | 108 | 110 | 106 | 107 | 1,600 |
تعطي إعادة التشكيل صفّين. الأسبوع المنتهي في 7 مارس: الافتتاح = أول افتتاح = 100؛ الأعلى = max(102, 104, 104, 105, 106) = 106؛ الأدنى = min(99, 100, 101, 101, 103) = 99؛ الإغلاق = آخر إغلاق = 105؛ الحجم = 1,000 + 1,200 + 900 + 1,100 + 1,500 = 5,700. الأسبوع المنتهي في 14 مارس: الافتتاح 105، والأعلى 110، والأدنى 103، والإغلاق 107، والحجم = 1,300 + 1,000 + 1,400 + 1,200 + 1,600 = 6,500.
التصفية: يعيد (df["close"] > df["open"]).sum() القيمة 7، لأن أيام 5 و10 و14 مارس وحدها أغلقت دون سعر افتتاحها. ويعيد df.loc["2025-03-05":"2025-03-07", "close"] القيم 102 و104 و105.
خطأ شائع
df.iloc[0:5] خمسة صفوف (المواضع من 0 إلى 4)، لكن df.loc["2025-03-03":"2025-03-07"] يعيد كل الصفوف حتى 7 مارس ضمنًا. استخدم iloc لـ «أول N صف» أو «آخر شمعة»، واستخدم loc مع تواريخ صريحة للفترات.نشاط تطبيقي
باستخدام جدول الشموع العشر أعلاه والعمل على الورق: (أ) اكتب تعبير pandas الذي يحدّد الشموع من 10 إلى 12 مارس ضمنًا؛ (ب) اذكر ما يعيده df.iloc[-3:]["close"].tolist()؛ (ج) احسب الشمعة الشهرية الوحيدة التي سيُنتجها df.resample("ME").agg(rules)؛ (د) اشرح ما الخطأ الذي يحدث إذا كتب أحدهم df.resample("ME").last() لجميع الأعمدة.
عرض الحل
(أ) df.loc["2025-03-10":"2025-03-12"]، ثلاثة صفوف مع تضمين الطرفين.
(ب) آخر ثلاثة أسعار إغلاق: [107, 108, 107].
(ج) صف واحد مسمّى بتاريخ 31 مارس 2025 (نهاية الشهر): الافتتاح 100 (الأول)، والأعلى 110 (الأقصى)، والأدنى 99 (الأدنى)، والإغلاق 107 (الأخير)، والحجم 12,200 (5,700 + 6,500).
(د) يأخذ .last() القيمة الأخيرة لكل عمود: فيصبح الأدنى الشهري 106 بدلًا من 99، والافتتاح 108 بدلًا من 100، والحجم 1,600 بدلًا من 12,200. مرّر دائمًا القواعد الخاصة بكل عمود.
القيود: لا يتضمن المثال عطلات أو أيامًا مفقودة؛ ومع البيانات الحقيقية، فإن الأسبوع الذي يتضمن عطلة يجمّع ببساطة أربع شموع، وتظهر تسمية الشهر «31 مارس» حتى لو كان آخر يوم تداول هو 28 مارس.
أهم النقاط
- تعيش بيانات الأسعار في إطار DataFrame ذي فهرس DatetimeIndex؛ تحقّق من
df.index.dtypeقبل أي شيء آخر. - يحدّد
locحسب التسمية ويشمل نهاية الشريحة؛ ويحدّدilocحسب الموضع ويستبعدها. - تحلّ الأقنعة المنطقية المجمّعة باستخدام
&و|و~محلّ الحلقات في التصفية، ويعدّ.sum()على القناع الحالات المطابقة. - أعِد تشكيل بيانات OHLCV باستخدام first/max/min/last/sum، واستخدم الاسمين المستعارين
"W-FRI"و"ME"، وتذكّر آلية النسخ عند الكتابة في pandas 3.0 عند الإسناد.
الخطوة التالية
يقدّم الدرس 4 بيانات حقيقية: قراءة ملفات CSV وواجهات API المجانية، وفهم الأسعار المعدّلة مقابل غير المعدّلة، والتعامل مع القيم المفقودة والمناطق الزمنية.
تقييم ذاتي
أجب عن الأسئلة، ثم تحقّق من إجاباتك. يمكنك إعادة المحاولة بقدر ما تشاء.
تقييم ذاتي تلقائي لمراجعتك الشخصية. تُفحَص إجاباتك في متصفحك ولا نطّلع عليها ولا نقيّمها. هذا ليس امتحانًا ولا مؤهّلًا.
تقدّمك
«مكتمل» يعني فقط أنك علّمت الدرس كمنتهٍ. وهو ليس اختبارًا لفهمك. يُحفظ التقدّم والملاحظات فقط في هذا المتصفح على هذا الجهاز — وليس في حساب.