معالجة القيم المفقودة
اكتشاف القيم المفقودة وحذفها وملؤها باستخدام isna() و dropna() و fillna() لتجهيز البيانات للتحليل.
- كشف القيم المفقودة باستخدام isna() و notna()
- حذف الصفوف أو الأعمدة ذات القيم المفقودة باستخدام dropna()
- ملء القيم المفقودة بأرقام محددة أو إحصاءات أو استراتيجيات باستخدام fillna()
- اختيار الاستراتيجية الصحيحة لمعالجة البيانات المفقودة
لماذا تهم القيم المفقودة
تحتوي كل مجموعة بيانات حقيقية تقريبًا على قيم مفقودة. إذا تجاهلتها، تعيد عمليات التجميع NaN، وتتعطل الرسوم البيانية، وتفشل نماذج التعلم الآلي. الخطوة الأولى في أي تحليل هي فهم ومعالجة البيانات المفقودة.
import pandas as pd
# titanic.csv ships with the course — load it from the browser file system.
df = pd.read_csv("titanic.csv")كشف القيم المفقودة
فحص عمود واحد:
print(df["Age"].isna().sum()) # 177 missing Age valuesفحص جميع الأعمدة دفعة واحدة:
print(df.isna().sum())المخرجات:
PassengerId 0
Survived 0
Pclass 0
Name 0
Sex 0
Age 177
SibSp 0
Parch 0
Ticket 0
Fare 0
Cabin 687
Embarked 2
dtype: int64
رؤية النسبة المئوية المفقودة:
print((df.isna().sum() / len(df) * 100).round(1))المخرجات:
Cabin 77.1%
Age 19.9%
Embarked 0.2%
...
عمود الأماكن Cabin مفقود بنسبة 77% ، أكثر من اللازم لملئه بشكل ذي معنى. العمر Age مفقود بنسبة 20% ، يستحق محاولة ملئه. أما Embarked ففيه قيمةان مفقودتان فقط ، سهل المعالجة.
حذف القيم المفقودة
حذف الصفوف التي تحتوي على أي قيم مفقودة:
df_clean = df.dropna()
print(df_clean.shape) # (183, 12) — lost most rowsهذا عدواني جدًا لمعظم مجموعات البيانات. تفقد 708 من أصل 891 صفًا.
حذف الصفوف التي تكون جميع قيمها مفقودة:
df_clean = df.dropna(how="all")حذف الصفوف ذات القيم المفقودة في أعمدة محددة:
df_clean = df.dropna(subset=["Age", "Embarked"])
print(df_clean.shape) # (712, 12) — much betterحذف الأعمدة التي تحتوي على عدد كبير جدًا من القيم المفقودة:
# Drop columns where more than 50% is missing
threshold = len(df) * 0.5
df_clean = df.dropna(thresh=threshold, axis=1)ملء القيم المفقودة
الملء بثابت:
df["Embarked"] = df["Embarked"].fillna("S") # most common portالملء بإحصائية:
df["Age"] = df["Age"].fillna(df["Age"].median())الملء الأمامي أو الخلفي ، مفيد للسلاسل الزمنية:
# Use the previous valid value to fill gaps
df["Price"] = df["Price"].ffill()
# Use the next valid value
df["Price"] = df["Price"].bfill()الملء بقيم مختلفة لكل عمود:
fill_values = {"Age": df["Age"].median(), "Embarked": "S", "Cabin": "Unknown"}
df = df.fillna(fill_values)اختيار استراتيجية
| السيناريو | الاستراتيجية |
|---|---|
| القيم المفقودة عشوائية وقليلة (< 5%) | الحذف باستخدام dropna(subset=[...]) |
| قيم مفقودة في عمود رقمي | الملء بالوسيط (منيع ضد القيم الشاذة) |
| قيم مفقودة في عمود فئوي | الملء بالمنوال أو “قيمة غير معروفة” |
| العمود مفقود فيه أكثر من 50% | حذف العمود كاملًا |
| بيانات سلاسل زمنية | استخدام ffill() أو bfill() |
مزالق شائعة
الملء قبل تقسيم بيانات التدريب/الاختبار ، هذا يُسرّب معلومات. احسب قيم الملء على بيانات التدريب فقط، ثم طبقها على الاثنين.
الحذف العدواني جدًا ، تحقق دائمًا من عدد الصفوف التي تخسرها. dropna() بدون وسائط يزيل غالبًا أكثر بكثير مما تتوقع.
نسيان التحقق ، شغّل دائمًا df.isna().sum() بعد الملء للتأكد من عدم بقاء أي قيم NaN.
جرّب بنفسك
من مجموعة بيانات تيتانيك:
- احسب النسبة المئوية للقيم المفقودة لكل عمود
- احذف عمود الـ Cabin (عدد كبير جدًا من القيم المفقودة)
- املأ Age بمتوسط العمر
- املأ Embarked بالقيمة الأكثر شيوعًا
- تحقق من عدم بقاء قيم مفقودة
import pandas as pd
# titanic.csv ships with the course — load it from the browser file system.
df = pd.read_csv("titanic.csv")
print((df.isna().sum() / len(df) * 100).round(1))
df = df.drop(columns=["Cabin"])
df["Age"] = df["Age"].fillna(df["Age"].median())
df["Embarked"] = df["Embarked"].fillna(df["Embarked"].mode()[0])
print(df.isna().sum())خلاصات رئيسية
- افحص دائمًا القيم المفقودة أولًا باستخدام
isna().sum()قبل اتخاذ قرار بشأن الاستراتيجية dropna()قوي لكنه غالبًا عدواني جدًا بدونsubsetأوthresh- الملء بالوسيط أو المنوال عبر
fillna()هو أكثر استراتيجيات الملء شيوعًا - الأعمدة التي بها أكثر من 50% قيم مفقودة أفضل حالًا بحذفها من ملئها
تحدي التطبيق
حمّل مجموعة بيانات تيتانيك وأنشئ نسخة نظيفة: احذف Cabin، واملأ Age بالوسيط، واملأ Embarked بالمنوال. ثم قارن معدل النجاة قبل التنظيف وبعده. هل غيّر التنظيف معدل النجاة الإجمالي؟ لماذا أو لماذا لا؟
1. كيف تتحقق من وجود قيم مفقودة في إطار البيانات؟
2. ماذا يفعل df.dropna()؟
3. كيف تملأ القيم المفقودة بمتوسط العمود؟