الوحدة 1 · أساسيات Python للمحللين
الحلقات والشروط والـ comprehensions
18 دقراءة 4 دتمرين Python
الدرس في لمحة
عالج كل صف في مجموعة بيانات باستخدام حلقات for، واتخذ القرارات بـ if و elif و else، واحسب العدد بالقواميس، واكتب المنطق نفسه بإيجاز على هيئة comprehensions.
- 1حلقة for
- 2اتخاذ القرارات بـ if و elif و else
- 3العدّ والجمع بحسب المجموعة
- 4الـ comprehensions: بناء القوائم في سطر واحد
- 5الحلقات مقابل pandas
لا فيديو هنا، بل الشيء الحقيقي: درس مكتوب وأمثلة قابلة للتشغيل واختبار وتدريب.
لديك ستة صفوف من ملف Cartwheel الفوضوي في قائمة من القواميس. تريد قيمتها الإجمالية، وكم جاء من كل قناة بيع، وأيّ الطلبات كانت كبيرة. كتابة سطر لكل صف تنجح مع ستة صفوف وتنهار مع ستة آلاف. حلقة التكرار (loop) تكتب المنطق مرة واحدة، وتكرّره Python لكل صف.
حلقة for
orders = [
{"order_id": 2574, "total": 65.0, "channel": "mobile app"},
{"order_id": 2069, "total": 18.0, "channel": "mobile app"},
{"order_id": 1200, "total": 33.0, "channel": "mobile app"},
{"order_id": 1809, "total": 35.0, "channel": "web"},
{"order_id": 1434, "total": 72.0, "channel": None},
{"order_id": 2089, "total": 58.0, "channel": "marketplace"},
]
grand_total = 0
for order in orders:
grand_total += order["total"]
print(grand_total)اقرأها هكذا: “لكل طلب في orders، شغّل الأسطر المُزاحة”. في كل دورة يشير الاسم order إلى القاموس التالي. والسطر grand_total += order["total"] اختصار لـ grand_total = grand_total + order["total"].
الإزاحة (indentation) في Python ليست زينة: الأسطر المُزاحة (أربع مسافات بحسب العُرف) هي جسم الحلقة، وأول سطر يعود إلى الهامش الأيسر يعمل بعد انتهاء الحلقة. لهذا تقع print خارجها: أنت تريد نتيجة واحدة، لا ستًا.
اتخاذ القرارات بـ if و elif و else
الشروط تتيح لكل صف أن يسلك مسارًا مختلفًا. فريق العمليات في Cartwheel يصنّف الطلبات بحسب حجمها:
totals = [65.0, 18.0, 33.0, 35.0, 72.0, 58.0, 329.0]
for t in totals:
if t < 50:
size = "small"
elif t < 150:
size = "medium"
else:
size = "large"
print(t, size)تختبر Python الشروط من الأعلى إلى الأسفل ولا تشغّل إلا أول فرع صحيح. الترتيب مهم: لو جاء اختبار الـ 150 أولًا، لصُنّف كل طلب صغير على أنه متوسط أيضًا، لأن 18 أقل من 150 كذلك. ضع الشرط الأضيق أولًا، أو اجعل الشروط غير متداخلة.
تستطيع دمج الشروط بـ and وor وnot. وتتيح لك Python أيضًا تسلسل المقارنات كما تكتبها في الرياضيات، وهذا مفيد مع النطاقات:
t = 89.0
channel = "web"
print(t >= 50 and channel == "web") # both must be true
print(50 <= t < 150) # chained: at least 50 and below 150
print(not channel == "marketplace") # flips True and Falseوحين تحتاج أيضًا موقع كل عنصر، لقائمة مرتّبة أو لرسالة مثل “الصف 3 معطوب”، غلّف القائمة بـ enumerate()، التي تعطيك الموقع والعنصر معًا: for position, t in enumerate(totals, start=1):. فضّلها على عدّ المواقع بيدك في متغيّر منفصل.
العدّ والجمع بحسب المجموعة
أكثر أنماط الحلقات فائدة في التحليل هو “لكل فئة، اجمع شيئًا”. يحتفظ القاموس بمجموع متراكم لكل مفتاح:
orders = [
{"order_id": 2574, "total": 65.0, "channel": "mobile app"},
{"order_id": 2069, "total": 18.0, "channel": "mobile app"},
{"order_id": 1200, "total": 33.0, "channel": "mobile app"},
{"order_id": 1809, "total": 35.0, "channel": "web"},
{"order_id": 1434, "total": 72.0, "channel": None},
{"order_id": 2089, "total": 58.0, "channel": "marketplace"},
]
revenue_by_channel = {}
for order in orders:
channel = order["channel"] or "unknown"
revenue_by_channel[channel] = revenue_by_channel.get(channel, 0) + order["total"]
for channel, revenue in revenue_by_channel.items():
print(channel, revenue)تفصيلان يحملان هذا الكود. revenue_by_channel.get(channel, 0) تعيد المجموع المتراكم حتى الآن، أو 0 في أول مرة تظهر فيها القناة. وorder["channel"] or "unknown" تستبدل None بتسمية مقروءة، لأن None تُعامَل كقيمة خاطئة، وor تعيد الطرف الأيمن حين يكون الأيسر خاطئًا.
هذا groupby مكتوب باليد. في الدرس 4.1 تنجزه pandas في سطر واحد، وأنت الآن تعرف ما يفعله ذلك السطر في الخلفية: المرور على الصفوف، ومعرفة مجموعة كل صف، وتحديث مجموع تلك المجموعة.
الـ comprehensions: بناء القوائم في سطر واحد
كثيرًا ما توجد الحلقة فقط لتبني قائمة جديدة. والـ list comprehension تقول ذلك مباشرة:
totals = [65.0, 18.0, 33.0, 35.0, 72.0, 58.0, 329.0]
with_rise = [round(t * 1.05, 2) for t in totals]
large = [t for t in totals if t >= 60]
print(with_rise)
print(large, len(large))اقرأ [t for t in totals if t >= 60] هكذا: “t، لكل t في totals، إذا كانت t 60 على الأقل”. الجزء الذي قبل for هو ما يدخل القائمة، والـ if في النهاية تصفّي. والـ dictionary comprehension تعمل بالطريقة نفسها مع زوج key: value:
countries = ["Canada", "united kingdom", "UNITED KINGDOM", "Saudi Arabia"]
clean = [c.strip().title() for c in countries]
print(clean)
print(sorted(set(clean))) # unique values, sorted
print({c: len(c) for c in set(clean)})الـ set لا يحتفظ إلا بالقيم الفريدة، فيدمج set(clean) الكتابتين المختلفتين للمملكة المتحدة في واحدة بعد تنظيفهما. ستطبّق الإصلاح نفسه على عمود كامل باستخدام pandas في الدرس 3.2.
الحلقات مقابل pandas
في pandas لن تكتب حلقة على الصفوف تقريبًا أبدًا. orders["total"].sum() تقوم بحلقة الجمع، وorders.groupby("channel")["total"].sum() تقوم بنمط القاموس السابق، وكلاهما بكود مُترجَم سريع. فلماذا تتعلّم الحلقات؟ لأنها طريقتك للتحقّق من فهمك لما تفعله عملية pandas، ولأن كثيرًا من العمل الحقيقي (المرور على ملفات، أو على أشهر، أو على قائمة دول لبناء تقرير) يبقى حلقة تحيط بكود pandas.
في التمرين تلخّص اثني عشر صفًا بحسب الدولة. ثم تغلّف منطقًا كهذا في دوال قابلة لإعادة الاستخدام، وتتعلّم قراءة رسائل الخطأ التي تعرضها Python.
أهم النقاط
- حلقة
forتشغّل جسمها المُزاح (indented) مرة لكل عنصر؛ أنشئ المتغيّرات التراكمية مثلtotal = 0قبل الحلقة، لا داخلها. - سلسلة
if/elif/elseتفحص الشروط من الأعلى إلى الأسفل، ولا تشغّل إلا أول فرع يكون شرطه صحيحًا. - النمط
counts[key] = counts.get(key, 0) + 1هو الطريقة المعتادة للعدّ أو الجمع بحسب المجموعة باستخدام قاموس. - الـ list comprehension بالشكل
[expr for x in items if condition]تبني قائمة جديدة في سطر واحد مقروء. - في pandas نادرًا ما تكتب حلقات، لأن العمليات على الأعمدة تقوم بالتكرار نيابةً عنك؛ لكن الحلقات تبقى طريقتك لفهم ما تفعله تلك العمليات.