مشروع: بيانات عربية وسخة
درس 9 من 9
9مشروع: بيانات عربية وسخة
الصورة الكبيرةمشروع المرحلة الأولى: مجموعة عربية حقيقية تخرج منها نظيفة، ومعها تقرير يدافع عن كل صف حذفته وكل خانة عوّضتها.
ماذا تشاهد في الرسم: سبع كتابات لأسماء المدن تدخل دالة التطبيع، وتحت كل واحدة ما تصير إليه. الحركات والتطويل والمسافة الزائدة والهمزة والتاء المربوطة تختفي، فتبقى ثلاث قيم يمكن التجميع عليها بأمان.
خارطة هذا الجزء
المفاهيم بالترتيب، اضغط أيًّا منها للقفز إليه:
طريقان إلى نفس الفكرة
البيانات الحقيقية تأتي متّسخة: أسماء مكتوبة بطرق مختلفة، وتواريخ بصيغ متعددة، وخانات فارغة، وتكرار. التنظيف مثل غسل الخضار قبل الطبخ. وفي هذا المشروع لا تنظّف فقط، بل تكتب لماذا حذفت كل صف، حتى يثق بك من يقرأ نتائجك.
خطوات التنظيف: توحيد النص العربي (الهمزات والتاء المربوطة والتشكيل والأرقام)، وتحويل الأنواع والتواريخ، وإزالة التكرار، ومعالجة الناقص والشاذ. تسجّل كل عملية وعدد الصفوف قبلها وبعدها في تقرير قابل لإعادة التشغيل، حتى تتكرر النتيجة نفسها على نسخة جديدة من البيانات.
قبل أن تبدأ
🗂️الإطارات والنقص
تستخدم groupby والدمج وتعرف الفرق بين حذف الناقص وتعويضه، من درس الإطارات.
📊الرسوم الثلاثة
ترسم مدرّجًا ومبعثرًا وصندوقًا، وتطبّق قاعدة المدى الربيعي من درس الرسوم.
الفكرة الجوهرية
المشروع يمرّ على أربع خطوات بالترتيب: تطبيع النص العربي، ثم المكرّر والناقص، ثم ثلاثة رسوم، ثم تقرير يدافع عن كل قرار.
1طبّع النص العربي أولًا
اختر مجموعة عربية حقيقية فيها نص وأرقام وقيم ناقصة، وبحجم تستطيع فحصه في جلسة واحدة. الصغير المفهوم أفضل من الكبير المجهول.
أول ما تفعله بها هو التطبيع: توحيد الهمزات والألف المقصورة والتاء المربوطة، وحذف الحركات والتطويل، وضغط المسافات.
import re
import unicodedata
HARAKAT = re.compile(r"[\u064B-\u0652\u0640]")
def normalise(text):
text = unicodedata.normalize("NFKC", text.strip())
text = HARAKAT.sub("", text)
text = text.replace("أ", "ا").replace("إ", "ا").replace("آ", "ا")
text = text.replace("ى", "ي").replace("ة", "ه")
return re.sub(r"\s+", " ", text)
raw = ["الرِّياض", "الريَاض ", "الـرياض", "جدة", "جده", "أبها", "ابها"]
cleaned = [normalise(value) for value in raw]
print(cleaned)
print(len(set(raw)), "->", len(set(cleaned)))
سبع كتابات مختلفة صارت ثلاث قيم. لاحظ أن الـرياض بالتطويل، والرِّياض بالحركات، والريَاض بمسافة زائدة كانت ثلاثة صفوف مختلفة في أي تجميع قبل هذه الدالة. ولاحظ أننا وحّدنا التاء المربوطة بالهاء فصارت جدة وجده قيمة واحدة.
2ثم المكرّر، ثم الناقص
الترتيب ليس اختياريًا. انظر إلى الرسم: التطبيع قبل حذف المكرّر، لأن «جدة» و«جده» نصّان مختلفان حرفيًا ومدينة واحدة فعلًا.
import pandas as pd
frame = pd.DataFrame({
"city": ["الرياض", "الرياض", "جده", "جدة", "الدمام"],
"orders": [120, 120, 90, 90, 40],
"revenue": [4800.0, 4800.0, 3150.0, 3150.0, None],
})
print("rows in:", len(frame))
frame["city"] = frame["city"].str.replace("ة", "ه", regex=False)
before = len(frame)
frame = frame.drop_duplicates()
print("dropped duplicates:", before - len(frame))
missing = int(frame["revenue"].isna().sum())
print("missing revenue:", missing)
per_order = (frame["revenue"] / frame["orders"]).dropna()
median_rate = float(per_order.median())
frame["revenue"] = frame["revenue"].fillna(frame["orders"] * median_rate)
print("median per order:", round(median_rate, 2))
print("rows out:", len(frame), "missing after:", int(frame["revenue"].isna().sum()))
print("total revenue:", round(float(frame["revenue"].sum()), 2))
خمسة صفوف دخلت وثلاثة خرجت. المكرّر سقط بعد التطبيع لا قبله، والناقص عُوّض بوسيط الإيراد لكل طلب مضروبًا في عدد الطلبات، أي بقيمة محسوبة من صفوف مشابهة لا بصفر. هذا قرار يجب أن يظهر في تقريرك بسطر واحد: «عوّضت إيراد الدمام بوسيط الإيراد لكل طلب 37.5 لأن عدد طلباتها معروف».
3ثلاثة رسوم وسطر لكل رسم
ارسم ثلاثة رسوم من الدرس السابق، ولكل رسم سؤاله. انظر إلى الرسم: المدرّج للتوزيع، والمبعثر لعمودين، والصندوق للشواذ.
الرسم بلا سطر تفسير لا يحسب في التسليم. السطر يربط ما رأيته بقرار اتخذته في البيانات.
4التقرير: ماذا ولكم صفًّا ولماذا
التقرير جدول من ثلاثة أعمدة: ما فعلته، وعلى كم صفًّا، ولماذا. انظر إلى الرسم: الأرقام التي يذكرها تقرير هذا المشروع.
كل حذف فرضية عن بياناتك. بعد شهر لن تتذكّر لماذا اختفت ثلاثمئة صف، وقارئك لن يثق برقم لا يعرف من أين جاء.
صفحة واحدة تكفي، والمهم أن تكون صادقة لا طويلة.
كيف يعمل، خطوة بخطوة: كيف تنظّف المجموعة بالترتيب الصحيح
طبّع النص أولًا: وحّد الهمزات والألف المقصورة والتاء المربوطة، واحذف الحركات والتطويل والمسافات الزائدة.
احذف المكرّر بعد التطبيع، فيُكتشف أن «جدة» و«جده» صفّ واحد مكرّر.
عالج النقص بقيمة مشتقّة من صفوف مشابهة، مثل وسيط الإيراد لكل طلب مضروبًا في عدد الطلبات.
اكتب كل قرار في التقرير: ماذا فعلت، وعلى كم صفًّا، ولماذا.
مثال محلول
جرّب بلا كود
خرافة مقابل حقيقة
| الخرافة | الحقيقة |
|---|---|
| ترتيب خطوات التنظيف لا يهمّ ما دامت كلها تُنفَّذ. | حذف المكرّر قبل التطبيع يترك «جدة» و«جده» صفّين مختلفين، فيبقى المكرّر ويفسد كل تجميع بعده. |
| الصف الذي فيه خانة فارغة واحدة يجب حذفه. | في جدول من عشرة أعمدة قد يحذف ذلك نصف البيانات، وغالبًا ليس عشوائيًا، فتخسر فئة كاملة بسبب عمود واحد. |
| التقرير إضافة اختيارية بعد التنظيف. | التقرير جزء من التسليم: بعد شهر لن تتذكّر لماذا اختفت ثلاثمئة صف، وقارئك لن يثق برقم لا يعرف مصدره. |
جرّب بنفسك
جمّعت الطلبات حسب المدينة فظهرت «جدة» و«جده» و«جـدة» كثلاث مدن. متى كان يجب أن تتدخّل؟
التطبيع يسبق كل شيء. الدمج اليدوي بعد التجميع يصلح هذه الحالة ويترك الحالة التالية، ويصير عملًا يدويًا يتكرّر مع كل تحديث للبيانات. الترميز مسألة مختلفة تمامًا: ملف بترميز خاطئ يعطيك حروفًا مشوّهة لا كتابات متعدّدة لنفس الاسم.
بطاقات مراجعة سريعة
تحقق من فهمك
لماذا نعوّض بالوسيط لا بالمتوسط عادة؟
لأن المتوسط ينجرّ مع الشواذّ كما رأيت في درس الرسم: قيمة واحدة ضخمة ترفع المتوسط وتجعل كل تعويضاتك مبالغًا فيها. الوسيط يبقى في منتصف التوزيع فعليًا. والأفضل من الاثنين، إن أمكن، قيمة محسوبة من صفوف مشابهة كما فعلنا هنا بالإيراد لكل طلب.
في المثال الثاني دخلت خمسة صفوف وخرجت ثلاثة. من أين جاء الفرق؟
من صفّين مكرّرين حُذفا بعد التطبيع: صف الرياض المكرّر، وصف جدة الذي كُتب «جده» مرة و«جدة» مرة. أما صف الدمام الناقص فعُوِّض ولم يُحذف.
مصادر هذا الدرس
مرتّبة بالنوع. ابدأ بالتوثيق الرسمي إذا تبي المرجع الدقيق، وبالمقال أو الفيديو إذا تبي الشرح أولًا.
توثيق رسمي1
مقالات1
خلّصت الدرس؟
سجّل الدخول ليُحفظ تقدّمك.