المحطّة ٢: جمع البيانات وتنظيفها
من الفوضى إلى جدولٍ نظيف: حلّل، نظّف، وعالج الناقص بوعي. ⏱ نحو 24 دقيقة.
- تحلّل بياناتٍ خامًّا إلى صفوفٍ منظّمة.
- تنظّف الفراغات وتحوّل الأنواع.
- تعالج القيَم الناقصة بقرارٍ صريحٍ ومبرّر.
- تمثّل كل صفٍّ قاموسًا جاهزًا للتحليل.
١البيانات الخامّ فوضى
البيانات في الواقع نادرًا ما تأتي نظيفة: فراغاتٌ زائدة، قيَمٌ ناقصة، أنواعٌ مختلطة (أرقامٌ مخزّنةٌ نصًّا). قبل أيّ تحليلٍ لا بدّ من التنظيف — وهو غالبًا أطول خطوةٍ في مشروع البيانات (تعلّمت أساسه في 244).
بياناتنا الخامّ (كأنها من ملفّ CSV): اسمٌ وثلاث درجاتٍ ونسبة حضور. لاحظ المشكلات: فراغاتٌ حول بعض الأسماء، ودرجةٌ ثالثةٌ مفقودةٌ عند طالبين:
raw = """name,g1,g2,g3,attendance سعود ,70,65,80,0.9نورة,55,40,60,0.6خالد ,90,85,88,0.95ريم,50,45,,0.5فهد,60,62,,0.8""" lines = raw.strip().split("\n")print("عدد الأسطر (مع الترويسة):", len(lines))print("الترويسة:", lines[0])print("أول سطر بيانات:", lines[1])
٢التحليل إلى صفوفٍ منظّمة
نحوّل كل سطرٍ إلى قاموس مفاتيحه أسماء الأعمدة (بنية تعلّمتها في 111 و101). ونعالج المشكلات أثناء ذلك: .strip() للفراغات، وتحويل الأرقام بـ int وfloat:
raw = """name,g1,g2,g3,attendance سعود ,70,65,80,0.9نورة,55,40,60,0.6خالد ,90,85,88,0.95ريم,50,45,,0.5فهد,60,62,,0.8""" lines = raw.strip().split("\n")rows = []for line in lines[1:]: # نتجاوز الترويسة name, g1, g2, g3, att = line.split(",") rows.append({ "name": name.strip(), # نزيل الفراغات "grades": [g1, g2, g3], # نصوص الآن، ننظّفها بعد قليل "attendance": float(att), }) print("عدد الطلاب:", len(rows))print("أول طالب:", rows[0]["name"], "— حضور", rows[0]["attendance"])
٣معالجة القيَم الناقصة
الدرجة الثالثة مفقودةٌ عند «ريم» و«فهد» (قيمةٌ فارغة بين الفاصلتين). قرارنا الصريح: نحسب المتوسّط من الدرجات الموجودة فقط (لا نعدّ المفقود صفرًا — فذلك يظلم الطالب). نحوّل ما ليس فارغًا إلى عددٍ ونتجاهل الفارغ:
cells = ["50", "45", ""] # درجات طالبٍ فيها واحدةٌ مفقودةgrades = [int(g) for g in cells if g.strip() != ""]print("الدرجات الموجودة:", grades)print("عددها:", len(grades))
توقّع وتحقّق
ما الذي يزيل الفراغات الزائدة حول نصّ؟
كيف نتجاهل القيمة المفقودة "" عند حساب المتوسّط؟
لماذا نحوّل "70" إلى int؟
لماذا نتجاوز lines[0]؟
الخلاصة
- البيانات الخامّ فوضى؛ التنظيف غالبًا أطول خطوةٍ في المشروع.
- كل سطرٍ ← قاموسٌ بمفاتيح الأعمدة؛ .
strip()للفراغات،int/floatللأرقام. - القيمة المفقودة لا تُعدّ صفرًا؛ رشّحها أو عوّضها بقرارٍ صريح.
- تجاوز سطر الترويسة دائمًا.
- بيانات نظيفة = أساسٌ لتحليلٍ وقرارٍ سليم.
تحدٍّ برمجي: تنظيف بيانات الطلاب
سهلنظّف البيانات الخامّ: حوّل كل سطرٍ إلى قاموسٍ باسمٍ منظّفٍ وقائمة درجاتٍ موجودةٍ (أعدادًا) ونسبة حضور، ثم اطبع عدد الطلاب وعدد الدرجات الموجودة لكلٍّ.
- تجاوز سطر الترويسة.
- نظّف الاسم بـ
.strip()، وحوّل الدرجات الموجودة إلىintمتجاهلًا الفارغ. - اطبع
عدد الطلاب: 5، ثم لكل طالبٍ سطرًاالاسم: عدد الدرجات.
ابدأ من هذا الكود، واضغط ▶ شغّل هنا لتكتب حلّك وتجرّبه مباشرة:
raw = """name,g1,g2,g3,attendance سعود ,70,65,80,0.9نورة,55,40,60,0.6خالد ,90,85,88,0.95ريم,50,45,,0.5فهد,60,62,,0.8""" lines = raw.strip().split("\n")# أكمل: حوّل الأسطر إلى صفوفٍ منظّفة، ثم اطبع المطلوب
💡 تلميح 1
[int(g) for g in [g1,g2,g3] if g.strip() != ""].💡 تلميح 2
f"{name}: {len(grades)}".حاول بنفسك أولًا؛ للمسألة أكثر من حلّ صحيح.
raw = """name,g1,g2,g3,attendance سعود ,70,65,80,0.9نورة,55,40,60,0.6خالد ,90,85,88,0.95ريم,50,45,,0.5فهد,60,62,,0.8""" lines = raw.strip().split("\n")rows = []for line in lines[1:]: name, g1, g2, g3, att = line.split(",") grades = [int(g) for g in [g1, g2, g3] if g.strip() != ""] rows.append({"name": name.strip(), "grades": grades, "attendance": float(att)}) print("عدد الطلاب:", len(rows))for r in rows: print(f"{r['name']}: {len(r['grades'])}")