ملء القيم المفقودة
استبدل NaN بثابت أو بمتوسط العمود أو بالملء الأمامي أو الخلفي باستخدام fillna() ومعلمة method الخاصة بها.
ملء القيم المفقودة درس مجاني في Pandas & NumPy Academy على CoddyKit. هذا هو الدرس 3 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Pandas & NumPy Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Pandas & NumPy Academy 4 دروس في المجموع.
مقدمة إلى fillna()
يعني الإسناد استبدال القيم المفقودة بقيمة بديلة معقولة بدلًا من حذف الصف. وتُعدّ fillna() في Pandas الأداة الأساسية لذلك؛ فهي تستبدل كل قيمة NaN في Series أو DataFrame بقيمة تحددها. وعلى خلاف الحذف، يحافظ الإسناد على جميع الصفوف، وهو أمر مهم خصوصًا عندما تكون البيانات محدودة أو يكون نمط فقدانها ذا دلالة.
أبسط صيغة هي تمرير قيمة مفردة: df['col'].fillna(0).
import pandas as pd
import numpy as np
df = pd.DataFrame({
'product': ['A', 'B', 'C', 'D'],
'price': [10.0, np.nan, 30.0, np.nan]
})
# Fill all NaN in 'price' with 0
filled = df['price'].fillna(0)
print(filled)
# 0 10.0
# 1 0.0
# 2 30.0
# 3 0.0الملء بمتوسط العمود أو وسيطه
يُعدّ الملء بمتوسط العمود (للتوزيعات المتماثلة) أو بوسيطه (للتوزيعات الملتوية) من أكثر استراتيجيات الإسناد شيوعًا. تمثل هذه الإحصاءات النزعة المركزية للبيانات، ولذلك تقلل تشويه توزيع العمود. احسب الإحصاء دائمًا على تقسيم التدريب لتجنب تسرّب البيانات.
import pandas as pd
import numpy as np
df = pd.DataFrame({
'salary': [50000, np.nan, 70000, 80000, np.nan, 60000]
})
mean_salary = df['salary'].mean()
median_salary = df['salary'].median()
df['salary_mean_filled'] = df['salary'].fillna(mean_salary)
df['salary_median_filled'] = df['salary'].fillna(median_salary)
print(df)
# salary salary_mean_filled salary_median_filled
# 0 50000.0 50000.0 50000.0
# 1 NaN 65000.0 65000.0
# 2 70000.0 70000.0 70000.0ملء الأعمدة الفئوية بالمنوال
بالنسبة إلى الأعمدة الفئوية، لا معنى للملء بالمتوسط أو الوسيط. بدلًا من ذلك، استخدم المنوال، أي القيمة الأكثر تكرارًا. تعيد Series.mode()[0] القيمة الأكثر شيوعًا، ويتعامل [0] مع الحالة التي يوجد فيها أكثر من منوال.
import pandas as pd
import numpy as np
df = pd.DataFrame({
'status': ['active', 'inactive', None, 'active', None, 'active']
})
most_common = df['status'].mode()[0]
print('Mode:', most_common) # active
df['status'] = df['status'].fillna(most_common)
print(df['status'].tolist())
# ['active', 'inactive', 'active', 'active', 'active', 'active']الملء إلى الأمام باستخدام ffill()
ينشر الملء إلى الأمام (ويُسمى أيضًا last-observation-carried-forward أو LOCF) آخر قيمة صالحة (غير NaN) إلى الأمام لملء مواضع NaN اللاحقة. وهو مناسب جدًا لبيانات السلاسل الزمنية التي تظل فيها القياسات ثابتة حتى تحديثها، مثل حالة الجهاز أو مستويات الأسعار أو قراءات المستشعر التي لا تتغير إلا عند وقوع أحداث محددة.
import pandas as pd
import numpy as np
price = pd.Series(
[100, np.nan, np.nan, 105, np.nan, 110],
index=pd.date_range('2024-01', periods=6, freq='ME')
)
filled = price.ffill()
print(filled)
# 2024-01-31 100.0
# 2024-02-29 100.0
# 2024-03-31 100.0
# 2024-04-30 105.0
# 2024-05-31 105.0
# 2024-06-30 110.0الملء إلى الخلف باستخدام bfill()
ينشر الملء إلى الخلف (next-observation-carried-backward أو NOCB) القيمة الصالحة التالية إلى الخلف لملء مواضع NaN السابقة. ويفيد ذلك عندما تعلم أن البيانات المستقبلية تملأ القيم الماضية المفقودة؛ فمثلًا، إذا استلمت بيانات نهاية الشهر وتحتاج إلى ملء أيام ذلك الشهر السابقة بأثر رجعي قبل وصول التقرير.
import pandas as pd
import numpy as np
df = pd.DataFrame({'value': [np.nan, np.nan, 3, np.nan, 5]})
print(df['value'].bfill())
# 0 3.0
# 1 3.0
# 2 3.0
# 3 5.0
# 4 5.0
# dtype: float64المعامل limit للملء إلى الأمام والخلف
يقبل كل من ffill() وbfill() معاملًا باسم limit يحدد عدد قيم NaN المتتالية التي يمكن ملؤها. وهذا مهم عندما تريد تمرير قيمة إلى الأمام عبر فجوة قصيرة فقط؛ إذ ينبغي أن تبقى الفجوات الطويلة على هيئة NaN للإشارة إلى أن البيانات مفقودة فعلًا وليست متأخرة فحسب.
import pandas as pd
import numpy as np
s = pd.Series([1.0, np.nan, np.nan, np.nan, 5.0])
# Fill only the first NaN gap, leave the rest
print(s.ffill(limit=1))
# 0 1.0
# 1 1.0 <- filled
# 2 NaN <- still NaN (limit reached)
# 3 NaN
# 4 5.0ملء الأعمدة المختلفة بطرق مختلفة
في DataFrame حقيقي، قد تحتاج الأعمدة المختلفة إلى استراتيجيات ملء مختلفة. مرّر قاموسًا إلى fillna() تكون مفاتيحه أسماء الأعمدة وقيمه هي قيم الملء. يطبّق ذلك إسنادًا خاصًا بكل عمود في استدعاء واحد، وهو أنظف من تسلسل عدة استدعاءات منفردة لـ fillna.
import pandas as pd
import numpy as np
df = pd.DataFrame({
'age': [25, np.nan, 30],
'income': [50000, np.nan, 70000],
'country': ['USA', np.nan, 'UK']
})
fill_values = {
'age': df['age'].median(),
'income': df['income'].mean(),
'country': 'Unknown'
}
filled = df.fillna(fill_values)
print(filled)
# age income country
# 0 25.0 50000.0 USA
# 1 27.5 60000.0 Unknown
# 2 30.0 70000.0 UKالإسناد المراعي للمجموعات
تتمثل إحدى الاستراتيجيات الأكثر تطورًا في ملء قيم NaN بمتوسط المجموعة أو وسيطها بدلًا من متوسط العمود ككل. فمثلًا، يمكن ملء راتب مفقود بوسيط الرواتب ضمن فئة الوظيفة نفسها. يحافظ ذلك على بنية المجموعات الفرعية وينتج قيمًا مسندة أكثر واقعية من استخدام إحصاء عام.
import pandas as pd
import numpy as np
df = pd.DataFrame({
'dept': ['Eng', 'Eng', 'HR', 'HR', 'Eng'],
'salary': [90000, np.nan, 50000, np.nan, 110000]
})
# Fill salary NaN with the median salary for each department
df['salary'] = df.groupby('dept')['salary'].transform(
lambda x: x.fillna(x.median())
)
print(df)
# dept salary
# 0 Eng 90000.0
# 1 Eng 100000.0 <- group median (90k+110k)/2
# 2 HR 50000.0
# 3 HR 50000.0
# 4 Eng 110000.0الملء بقيمة ثابتة مميِّزة
يكون الإسناد المناسب أحيانًا هو قيمة مميِّزة تشير إلى «غير معروف» بدلًا من كونها قياسًا حقيقيًا. فمثلًا، استخدم -1 للعمر غير المعروف، أو 'N/A' للفئة غير المعروفة، أو False لعلامة منطقية غير معروفة. تكون القيم المميِّزة مناسبة عندما يتحقق منها الكود اللاحق صراحةً ويتعامل معها بشكل مختلف عن البيانات الحقيقية.
import pandas as pd
import numpy as np
df = pd.DataFrame({
'user_id': [1, 2, 3],
'referral_source': ['email', np.nan, 'ad'],
'trial_days': [14, np.nan, 7]
})
df['referral_source'] = df['referral_source'].fillna('unknown')
df['trial_days'] = df['trial_days'].fillna(-1).astype(int)
print(df)
# user_id referral_source trial_days
# 0 1 email 14
# 1 2 unknown -1
# 2 3 ad 7تسلسل fillna() في خط أنابيب
مثل جميع أساليب Pandas، تعيد fillna() DataFrame جديدًا، وتندمج بسلاسة في تسلسل أساليب. يؤدي استدعاء .fillna() بعد .dropna() إلى تطبيق استراتيجية من خطوتين: حذف الصفوف التي تفتقد أعمدة أساسية، ثم ملء قيم NaN الاختيارية المتبقية بقيم افتراضية معقولة، وكل ذلك ضمن خط أنابيب واحد سهل القراءة.
import pandas as pd
import numpy as np
df = pd.DataFrame({
'user_id': [1, None, 3, 4],
'score': [88, 95, np.nan, 76],
'label': ['A', 'B', None, 'D']
})
cleaned = (
df
.dropna(subset=['user_id'])
.fillna({'score': df['score'].mean(), 'label': 'Unknown'})
)
print(cleaned)
# user_id score label
# 0 1.0 88.0 A
# 2 3.0 86.3 Unknown
# 3 4.0 76.0 Dالتحقق من عدم بقاء أي NaN
بعد الإسناد، احرص دائمًا على التحقق من عدم بقاء قيم NaN في الأعمدة التي استهدفتها. استدعِ df.isna().sum() أو أكد أن العدد يساوي صفرًا. ويعني وجود عدد غير صفري على نحو غير متوقع أن fillna لم يعالج حالة ما، ربما لأن نوع بيانات أحد الأعمدة منع الملء، أو لأنك نسيت عمودًا في قاموسك.
import pandas as pd
import numpy as np
df = pd.DataFrame({'a': [1.0, np.nan, 3.0], 'b': [np.nan, 2.0, 3.0]})
filled = df.fillna(0)
# Verify
assert filled.isna().sum().sum() == 0, 'Some NaN remain!'
print('All NaN filled successfully')
print(filled.isna().sum())
# a 0
# b 0
# dtype: int64تحقق سريع
اختبر فهمك لملء القيم المفقودة في Pandas.
مراجعة الدرس
تعلمت في هذا الدرس أن fillna(scalar) يستبدل كل قيم NaN بثابت، وأن fillna(mean/median) يُسند القيم باستخدام إحصاءات العمود، وأن ffill()/bfill() ينشران القيم المجاورة في السلاسل الزمنية. مرّر قاموسًا إلى fillna() لتطبيق استراتيجيات خاصة بكل عمود، واستخدم groupby().transform() للإسناد المراعي للمجموعات. بعد ذلك سنتناول الاستيفاء ومتى تختار تقنيات الإسناد المتقدمة.
الأسئلة الشائعة
هل درس «ملء القيم المفقودة» مجاني؟
نعم — نص درس «ملء القيم المفقودة» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Pandas & NumPy Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Pandas & NumPy Academy 4 دروس في المجموع.
ماذا ستتعلم في «ملء القيم المفقودة»؟
استبدل NaN بثابت أو بمتوسط العمود أو بالملء الأمامي أو الخلفي باستخدام fillna() ومعلمة method الخاصة بها. تتمرن على Pandas & NumPy Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ Pandas & NumPy Academy؟
لا تُشترط خبرة سابقة. Pandas & NumPy Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 3 من أصل 4.
كم من الوقت يستغرق درس «ملء القيم المفقودة»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس Pandas & NumPy Academy هذا؟
نعم. كل درس في Pandas & NumPy Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- اكتشاف القيم المفقودة
- حذف القيم المفقودة
- ملء القيم المفقودة
- الاستيفاء والتعويض المتقدم