الدرس 15 · الوحدة 8: تحليل وتحويل البيانات المجمعة
القيم المفقودة والمكرّرة
البيانات الحقيقية ناقصة ومكرّرة؛ كيف ننظّفها دون أن نشوّهها؟ ⏱ نحو 45 دقيقة.
بعد هذا الدرس ستستطيع أن:
- تكتشف المفقود والمكرّر.
- تختار بين الحذف والملء بحكمة.
- تملأ الرقمي بالوسيط والفئوي ببديل معقول.
- تزيل التكرار الكامل أو حسب عمود.
١البيانات الحقيقية ناقصة وفوضوية
بيانات الويب الحقيقية مليئة بالثقوب: حقلٌ لم يُملأ، سطرٌ مكرّر بسبب خطأ تتبّع. التنظيف نصف عمل عالِم البيانات. أول خطوة: اكتشف المشكلة.
import pandas as pdimport numpy as npdf = pd.DataFrame({ "user": ["u1","u2","u3","u4","u2","u5"], "age": [25, np.nan, 30, 42, np.nan, 19], "city": ["الرياض", "جدة", None, "الرياض", "جدة", "الدمام"], "spend":[300, 150, 200, np.nan, 150, 90],})print("قيم مفقودة في كل عمود:")print(df.isna().sum())print("صفوف مكرّرة:", int(df.duplicated().sum()))
>>> %Run main.py
قيم مفقودة في كل عمود:
user 0
age 2
city 1
spend 1
dtype: int64
صفوف مكرّرة: 1
>>>
isna() يعطي جدولًا منطقيًّا (مفقود؟)، و.sum() يعدّ المفقود لكل عمود. هذه أول لقطةٍ لصحّة بياناتك.
٢معالجة المفقود: حذف أم ملء؟
خياران، ولكلٍّ موضعه:
| الخيار | الدالة | متى |
|---|---|---|
| الحذف | dropna() | المفقود قليل، أو الصفّ بلا قيمة بدونه |
| الملء بقيمة | fillna(x) | نريد إبقاء الصفّ، ولدينا بديلٌ معقول |
import pandas as pdimport numpy as npdf = pd.DataFrame({ "user": ["u1","u2","u3","u4","u2","u5"], "age": [25, np.nan, 30, 42, np.nan, 19], "city": ["الرياض", "جدة", None, "الرياض", "جدة", "الدمام"], "spend":[300, 150, 200, np.nan, 150, 90],})# املأ العمر المفقود بالوسيط، والمدينة بـ "غير معروف"df["age"] = df["age"].fillna(df["age"].median())df["city"] = df["city"].fillna("غير معروف")# احذف الصفوف التي ما زال فيها مفقود (spend)clean = df.dropna()print(clean)print("الصفوف الباقية:", len(clean))
>>> %Run main.py
user age city spend
0 u1 25.0 الرياض 300.0
1 u2 27.5 جدة 150.0
2 u3 30.0 غير معروف 200.0
4 u2 27.5 جدة 150.0
5 u5 19.0 الدمام 90.0
الصفوف الباقية: 5
>>>
٣إزالة التكرار
import pandas as pdimport numpy as npdf = pd.DataFrame({ "user": ["u1","u2","u3","u4","u2","u5"], "age": [25, np.nan, 30, 42, np.nan, 19], "city": ["الرياض", "جدة", None, "الرياض", "جدة", "الدمام"], "spend":[300, 150, 200, np.nan, 150, 90],})print("قبل:", len(df))# احذف الصفوف المكرّرة تمامًاdf2 = df.drop_duplicates()print("بعد حذف التكرار الكامل:", len(df2))# أو: احتفظ بأول ظهور لكل مستخدمdf3 = df.drop_duplicates(subset="user", keep="first")print("مستخدم فريد:", len(df3))
>>> %Run main.py
قبل: 6
بعد حذف التكرار الكامل: 5
مستخدم فريد: 5
>>>
drop_duplicates بلا وسائط يحذف الصفوف المتطابقة كليًّا. ومع subset يحذف التكرار في عمودٍ معيّن (كمستخدمٍ تكرّر).
توقّع وتحقّق
لعدّ القيم المفقودة لكل عمود:
لحذف الصفوف ذات القيم المفقودة:
لملء المفقود بقيمة:
لحذف الصفوف المكرّرة:
الخلاصة
- التنظيف نصف العمل؛ ابدأ باكتشاف المفقود (
isna().sum()) والمكرّر(duplicated()). - عالج المفقود بالحذف
(dropna)إن قلّ، أو الملء(fillna)إن أردت الإبقاء. - املأ الرقمي بالوسيط/المتوسط لا بصفر، والفئوي ببديلٍ معقول.
drop_duplicatesيزيل التكرار الكامل، وsubsetيزيله في عمودٍ بعينه.
تحدٍّ برمجي: نظّف الجدول
متقدماملأ spend المفقود بوسيطه، واحذف تكرار المستخدم (أول ظهور)، ثم اطبع عدد الصفوف الباقية ومجموع spend.
المطلوب:
- املأ
spendالمفقود بالوسيط. - احذف تكرار
user، واطبع عدد الصفوف ومجموعspendصحيحًا.
ابدأ من هذا الكود، واضغط ▶ شغّل هنا لتكتب حلّك وتجرّبه مباشرة:
import pandas as pdimport numpy as npdf = pd.DataFrame({ "user": ["u1","u2","u3","u4","u2","u5"], "age": [25, np.nan, 30, 42, np.nan, 19], "city": ["الرياض", "جدة", None, "الرياض", "جدة", "الدمام"], "spend":[300, 150, 200, np.nan, 150, 90],})# املأ spend بالوسيط، احذف تكرار user، ثم اطبع عدد الصفوف ومجموع spend
5
890
💡 تلميح 1
املأ:
df["spend"].fillna(df["spend"].median()).💡 تلميح 2
احذف التكرار:
drop_duplicates(subset="user").حاول بنفسك أولًا؛ للمسألة أكثر من حلّ صحيح.
import pandas as pdimport numpy as npdf = pd.DataFrame({ "user": ["u1","u2","u3","u4","u2","u5"], "age": [25, np.nan, 30, 42, np.nan, 19], "city": ["الرياض", "جدة", None, "الرياض", "جدة", "الدمام"], "spend":[300, 150, 200, np.nan, 150, 90],})df["spend"] = df["spend"].fillna(df["spend"].median())clean = df.drop_duplicates(subset="user", keep="first")print(len(clean))print(int(clean["spend"].sum()))