Pandas: معالجة القيم المفقودة
آخر تحديث: 2026-08-26
القيم المفقودة (NaN) هي العدو الأول لتنظيف البيانات — البيانات في العالم الحقيقي ليست مثالية أبدًا. عطل في المستشعر يترك قراءات درجة الحرارة مفقودة، ومستخدم يتجاوز حقلاً اختياريًا فتفقد قيمة العمر، ودمج نظام يمحو المعرفات. تقدم Pandas سلسلة أدوات متكاملة للكشف عن القيم المفقودة، وإسقاطها، وملئها، والتقريب لها. يرشدك هذا القسم خلال كل واحدة منها ويشرح كيفية العمل بأمان ضمن نمط النسخ عند الكتابة (Copy-on-Write).
1. ما ستتعلمه
- ❶ طبيعة ودلالات NaN
- ❷ الكشف باستخدام isnull / notnull
- ❸ إسقاط الصفوف/الأعمدة المفقودة باستخدام dropna
- ❹ ملء القيم المفقودة باستخدام fillna
- ❺ طرق الاستكمال (الاستيفاء) باستخدام interpolate
2. الفجوة في بيانات تمارين كارول
(1) نقطة الضعف: 30% من بيانات معدل ضربات القلب مفقودة
سجّل جهاز تتبع لياقة كارول بيانات لمعدل ضربات القلب لمدة 30 يومًا، لكن الإشارة انقطعت (NaN) في 9 أيام منها أثناء تمارينها:
import pandas as pd
import numpy as np
hr = pd.DataFrame({
'date': pd.date_range('2024-01-01', periods=30),
'heart_rate': [72, 75, np.nan, 78, np.nan, 80, 82, np.nan,
85, 88, np.nan, 90, 87, np.nan, 83, 80,
np.nan, 78, 76, np.nan, 74, 72, np.nan, 70,
68, np.nan, 65, 63, np.nan, 60]
})
print(f"Missing: {hr['heart_rate'].isnull().sum()} / {len(hr)}")
# Missing: 9 / 30
> **الخرج:** شغّل هذا في بيئة بايثون محلية (pandas 2.x). خادم Piston لا يحتوي على مكتبة pandas مثبتة مسبقًا — ثبّتها محليًا (`pip install pandas`) للمتابعة. قد تختلف القيم الفعلية قليًّا حسب إصدار pandas الخاص بك.
(2) الحل: أربع استراتيجيات، لكل منها حالة استخدام خاصة
| الاستراتيجية | الطريقة | متى نستخدمها |
|---|---|---|
| الكشف | isnull / notnull | لفهم توزيع القيم المفقودة |
| الحذف | dropna | عند قلة القيم المفقودة، والصفوف غير مهمة |
| التعبئة | fillna | عند وجود قيمة افتراضية معقولة |
| الاستكمال | interpolate | لبيانات السلاسل الزمنية ذات الاتجاه الواضح |
3. طبيعة NaN
(1) NaN لا يساوي NaN
▶ مثال: السلوك الخاص لـ NaN (الصعوبة ⭐)
import numpy as np
# NaN لا يساوي نفسه - هذا هو معيار IEEE 754
print(np.nan == np.nan) # False!
print(np.nan != np.nan) # True!
# استخدم np.isnan() للكشف عن NaN
print(np.isnan(np.nan)) # True
# يتعامل Pandas مع هذا داخليًا - isnull() تعمل بشكل صحيح
import pandas as pd
s = pd.Series([1, np.nan, 3, None, 5])
print(s.isnull())
# 0 False
# 1 True
# 2 False
# 3 True
# 4 False
> **الناتج:** قم بتشغيل هذا في بيئة Python محلية (pandas 2.x). خادم Piston لا يحتوي على pandas مثبتًا مسبقًا — قم بتثبيته محليًا (`pip install pandas`) للمتابعة. قد تختلف القيم الفعليّة قليًّا حسب إصدار pandas الخاص بك.
(2) أنواع القيم المفقودة في Pandas
| النوع | التمثيل المفقود | مثال |
|---|---|---|
| float64 | np.nan | قيمة الفاصلة العائمة المفقودة الافتراضية |
| int64 | لا يمكن تمثيل NaN أصليًّا → يتم التحويل تلقائيًّا إلى float64 | [1, None, 3] → float64 |
| كائن | None / np.nan | أعمدة من نوع مختلط |
| سلسلة | pd.NA | سلسلة قابلة لل_Null في Pandas 1.x+ |
| Int64 | pd.NA | عدد صحيح قابل لل_Null (حرف كبير I) |
| datetime64 | NaT | قيمة وقت مفقودة |
Int64، boolean، وstring) تستخدم pd.NA بدلاً من np.nan، مما يحل مشكلة عدم قدرة أعمدة الأعداد الصحيحة على تمثيل القيم المفقودة. قم بالتحويل عبر: df['col'].astype('Int64').
4. الكشف باستخدام isnull / notnull
(1) الكشف الأساسي
▶ مثال
> **Output:** Run this in a local Python environment (pandas 2.x). The Piston server does not have pandas pre-installed — install it locally (`pip install pandas`) to follow along. Actual values may vary slightly depending on your pandas version.
: كشف القيم المفقودة (الصعوبة ⭐)
import pandas as pd
import numpy as np
df = pd.DataFrame({
'name': ['Alice', 'Bob', 'Charlie', 'Carol', 'David'],
'age': [28, np.nan, 25, 30, np.nan],
'salary': [75000, 92000, np.nan, 88000, 105000],
'department': ['Sales', 'Engineering', np.nan, 'Sales', 'Management']
})
# Per-element detection
print(df.isnull())
# name age salary department
# 0 False False False False
# 1 False True False False
# 2 False False True True
# 3 False False False False
# 4 False True False False
# Per-column count
print(df.isnull().sum())
# name 0
# age 2
# salary 1
# department 1
# Total missing
print(f"Total missing: {df.isnull().sum().sum()}") # 4
# Not-null (inverse)
print(df.notnull().sum()) # count of non-missing per column
> **Output:** قم بتشغيل هذا في بيئة Python محلية (pandas 2.x). خادم Piston لا يحتوي على pandas مثبتًا مسبقًا — قم بتثبيته محليًا (`pip install pandas`) لمتابعة التوضيح. القيم الفعلية قد تختلف قليلاً حسب إصدار pandas الخاص بك.
(2) تصور وتحليل القيم المفقودة
▶ مثال
> **Output:** قم بتشغيل هذا في بيئة Python محلية (pandas 2.x). خادم Piston لا يحتوي على pandas مثبتًا مسبقًا — قم بتثبيته محليًا (`pip install pandas`) لمتابعة التوضيح. القيم الفعلية قد تختلف قليلاً حسب إصدار pandas الخاص بك.
: تحليل أنماط القيم المفقودة (الصعوبة ⭐⭐)
import pandas as pd
import numpy as np
df = pd.DataFrame({
'name': ['Alice', 'Bob', 'Charlie', 'Carol', 'David', 'Eve'],
'age': [28, np.nan, 25, 30, np.nan, 27],
'salary': [75000, 92000, np.nan, 88000, 105000, np.nan],
'department': ['Sales', 'Engineering', np.nan, 'Sales', 'Management', 'HR']
})
# Which rows have ANY missing?
rows_with_missing = df[df.isnull().any(axis=1)]
print(f"Rows with missing values: {len(rows_with_missing)}")
# 3 rows (Bob, Charlie, David)
# Which columns have missing?
cols_with_missing = df.columns[df.isnull().any()].tolist()
print(f"Columns with missing: {cols_with_missing}")
# ['age', 'salary', 'department']
# Missing percentage per column
missing_pct = (df.isnull().sum() / len(df) * 100).round(1)
print(missing_pct[missing_pct > 0])
# age 33.3%
# salary 33.3%
# department 16.7%
> **Output:** قم بتشغيل هذا في بيئة Python محلية (pandas 2.x). خادم Piston لا يحتوي على pandas مثبتًا مسبقًا — قم بتثبيته محليًا (`pip install pandas`) لمتابعة التوضيح. القيم الفعلية قد تختلف قليلاً حسب إصدار pandas الخاص بك.
5. إسقاط القيم المفقودة باستخدام dropna
(1) الإسقاط الأساسي
▶ مثال
> **الخرج:** شغّل هذا في بيئة بايثون محلية (pandas 2.x). خادم Piston لا يحتوي على pandas مثبت مسبقًا — قم بتثبيته محليًا (`pip install pandas`) للمتابعة. قد تختلف القيم الفعلية قليًلاً حسب إصدار pandas الخاص بك.
: الإسقاط باستخدام dropna (الصعوبة ⭐)
import pandas as pd
import numpy as np
df = pd.DataFrame({
'name': ['Alice', 'Bob', 'Charlie', 'Carol', 'David'],
'age': [28, np.nan, 25, 30, np.nan],
'salary': [75000, 92000, np.nan, 88000, 105000]
})
# Drop rows with ANY missing (default)
print(df.dropna())
# name age salary
# 0 Alice 28.0 75000.0
# 3 Carol 30.0 88000.0
# Drop rows where ALL values are missing
print(df.dropna(how='all'))
# Drop columns with any missing
print(df.dropna(axis=1))
# name
# 0 Alice
# 1 Bob
# ...
# Drop rows with threshold (keep rows with >= N non-missing)
print(df.dropna(thresh=2)) # at least 2 non-NaN values
# name age salary
# 0 Alice 28.0 75000.0
# 1 Bob NaN 92000.0
# 3 Carol 30.0 88000.0
# 4 David NaN 105000.0
> **الخرج:** شغّل هذا في بيئة بايثون محلية (pandas 2.x). خادم Piston لا يحتوي على pandas مثبت مسبقًا — قم بتثبيته محليًا (`pip install pandas`) للمتابعة. قد تختلف القيم الفعلية قليًلاً حسب إصدار pandas الخاص بك.
(2) تفاصيل معاملات dropna
| المعامل | القيمة الافتراضية | الوصف |
|---|---|---|
| axis | 0 | 0 = إسقاط الصفوف، 1 = إسقاط الأعمدة |
| how | 'any' | 'any' = إسقاط إذا كان هناك أي قيمة مفقودة، 'all' = إسقاط فقط إذا كانت جميع القيم مفقودة |
| thresh | None | الاحتفاظ بالصفوف التي تحتوي على N قيمة غير مفقودة على الأقل |
| subset | None | التحقق فقط من الأعمدة المحددة |
▶ مثال
> **الخرج:** شغّل هذا في بيئة بايثون محلية (pandas 2.x). خادم Piston لا يحتوي على pandas مثبت مسبقًا — قم بتثبيته محليًا (`pip install pandas`) للمتابعة. قد تختلف القيم الفعلية قليًلاً حسب إصدار pandas الخاص بك.
: التحقق على مستوى عمود معين باستخدام dropna (الصعوبة ⭐⭐)
import pandas as pd
import numpy as np
df = pd.DataFrame({
'name': ['Alice', 'Bob', 'Charlie', 'Carol', 'David'],
'age': [28, np.nan, 25, 30, np.nan],
'salary': [75000, 92000, np.nan, 88000, 105000],
'department': ['Sales', 'Engineering', 'Marketing', 'Sales', 'Management']
})
# Only drop rows where 'salary' is missing
# (keep rows with missing 'age' — we can impute age)
print(df.dropna(subset=['salary']))
# name age salary department
# 0 Alice 28.0 75000.0 Sales
# 1 Bob NaN 92000.0 Engineering
# 3 Carol 30.0 88000.0 Sales
# 4 David NaN 105000.0 Management
> **الخرج:** شغّل هذا في بيئة بايثون محلية (pandas 2.x). خادم Piston لا يحتوي على pandas مثبت مسبقًا — قم بتثبيته محليًا (`pip install pandas`) للمتابعة. قد تختلف القيم الفعلية قليًلاً حسب إصدار pandas الخاص بك.
6. ملء القيم المفقودة باستخدام fillna
(1) الملء بقيمة ثابتة
▶ مثال
> **الناتج:** شغّل هذا في بيئة بايثون محلية (pandas 2.x). خادم Piston لا يحتوي على pandas مثبّت مسبقاً — قم بتثبيته محلياً (`pip install pandas`) للمتابعة. قد تختلف القيم الفعلية قليلاً حسب إصدار pandas لديك.
: الملء بقيم ثابتة وإحصائية باستخدام fillna (الصعوبة ⭐⭐)
import pandas as pd
import numpy as np
df = pd.DataFrame({
'name': ['Alice', 'Bob', 'Charlie', 'Carol', 'David'],
'age': [28, np.nan, 25, 30, np.nan],
'salary': [75000, 92000, np.nan, 88000, 105000]
})
# Fill with constant
df_const = df.fillna({'age': 0, 'salary': 0})
print(df_const)
# Fill with mean (most common for numeric)
df_mean = df.copy()
df_mean['age'] = df_mean['age'].fillna(df_mean['age'].mean())
df_mean['salary'] = df_mean['salary'].fillna(df_mean['salary'].median())
print(df_mean)
# age: filled with 27.67, salary: filled with 88000.0
# Fill with forward fill (use previous value)
df_ffill = df.fillna(method='ffill')
print(df_ffill)
> **الناتج:** شغّل هذا في بيئة بايثون محلية (pandas 2.x). خادم Piston لا يحتوي على pandas مثبّت مسبقاً — قم بتثبيته محلياً (`pip install pandas`) للمتابعة. قد تختلف القيم الفعلية قليلاً حسب إصدار pandas لديك.
fillna(method=...) مُهمل — استخدم df.ffill() / df.bfill() بدلاً منه.
(2) الملء الأمامي / الخلفي
▶ مثال
> **الناتج:** شغّل هذا في بيئة بايثون محلية (pandas 2.x). خادم Piston لا يحتوي على pandas مثبّت مسبقاً — قم بتثبيته محلياً (`pip install pandas`) للمتابعة. قد تختلف القيم الفعلية قليلاً حسب إصدار pandas لديك.
: ffill و bfill (الصعوبة ⭐)
import pandas as pd
import numpy as np
# Time-series data — ffill makes sense here
ts = pd.DataFrame({
'date': pd.date_range('2024-01-01', periods=8),
'temperature': [22.5, np.nan, np.nan, 23.1, np.nan, 24.0, np.nan, 24.5]
})
# Forward fill (propagate last valid value)
print(ts.assign(temperature_ffill=ts['temperature'].ffill()))
# NaN → use previous non-NaN value
# Backward fill (propagate next valid value)
print(ts.assign(temperature_bfill=ts['temperature'].bfill()))
# NaN → use next non-NaN value
# Limit: only fill N consecutive NaN
print(ts.assign(temperature_limited=ts['temperature'].ffill(limit=1)))
# Only fill 1 consecutive NaN, leave the rest
> **الناتج:** شغّل هذا في بيئة بايثون محلية (pandas 2.x). خادم Piston لا يحتوي على pandas مثبّت مسبقاً — قم بتثبيته محلياً (`pip install pandas`) للمتابعة. قد تختلف القيم الفعلية قليلاً حسب إصدار pandas لديك.
7. الاستكمال (التوليف) باستخدام interpolate
(1) الاستكمال الخطي
▶ مثال
> **المخرجات:** قم بتشغيل هذا في بيئة Python محلية (pandas 2.x). خادم Piston لا يحتوي على مكتبة pandas مثبتة مسبقاً — قم بتثبيتها محلياً (`pip install pandas`) لمتابعة الشرح. قد تتغير القيم الفعلي قليلاً حسب إصدار pandas لديك.
: الاستكمال الخطي باستخدام interpolate (الصعوبة ⭐⭐)
import pandas as pd
import numpy as np
# بيانات معدل ضربات قلب كارول — الاستكمال الخطي هو الطبيعي
hr = pd.DataFrame({
'time_min': list(range(10)),
'heart_rate': [72, 75, np.nan, 78, np.nan, 80, 82, np.nan, 85, 88]
})
# الاستكمال الخطي (الافتراضي)
hr['hr_linear'] = hr['heart_rate'].interpolate()
print(hr[['time_min', 'heart_rate', 'hr_linear']])
# time 2: (75+78)/2 = 76.5
# time 4: (78+80)/2 = 79.0
# time 7: (82+85)/2 = 83.5
# الاستكمال بناءً على الفهرس مقابل الاستكمال الزمني
hr_ts = pd.DataFrame({
'heart_rate': [72, 75, np.nan, 78, np.nan, 80]
}, index=pd.to_timedelta([0, 5, 15, 20, 40, 45], unit='min'))
# الاستكمال الموزون زمنياً
hr_ts['hr_time'] = hr_ts['heart_rate'].interpolate(method='time')
print(hr_ts)
> **المخرجات:** قم بتشغيل هذا في بيئة Python محلية (pandas 2.x). خادم Piston لا يحتوي على مكتبة pandas مثبتة مسبقاً — قم بتثبيتها محلياً (`pip install pandas`) لمتابعة الشرح. قد تتغير القيم الفعلي قليلاً حسب إصدار pandas لديك.
(2) مقارنة طرق الاستكمال
| الطريقة | طريقة | متى تُستخدم |
|---|---|---|
| خطي | 'linear' | بيانات مأخوذة بانتظام، اتجاهات سلسة |
| موزون زمنياً | 'time' | فترات زمنية غير منتظمة |
| موزون بالفهرس | 'index' | تباعد فهرسي غير منتظم |
| تربيعي | 'quadratic' | اتجاهات منحنية |
| تكعيبي | 'cubic' | منحنيات سلسة |
| أقرب جار | 'nearest' | بيانات منفصلة / متدرجة |
| سبلاين | 'spline' | استكمال سلس (يتطلب معامل الترتيب) |
▶ مثال
> **المخرجات:** قم بتشغيل هذا في بيئة Python محلية (pandas 2.x). خادم Piston لا يحتوي على مكتبة pandas مثبتة مسبقاً — قم بتثبيتها محلياً (`pip install pandas`) لمتابعة الشرح. قد تتغير القيم الفعلي قليلاً حسب إصدار pandas لديك.
: مقارنة طرق الاستكمال (الصعوبة ⭐⭐)
import pandas as pd
import numpy as np
s = pd.Series([0.0, np.nan, np.nan, np.nan, np.nan, 5.0, 10.0])
print("linear: ", s.interpolate(method='linear').tolist())
# [0.0, ~1.67, ~3.33, 5.0, ~6.67, 5.0, 10.0]
# لكن هذا يتضمن حدود NaN.
print("linear (trim):", s.dropna().interpolate(method='linear').tolist())
# يوضح الاستكمال الخطي فقط.
# التربيعي يحتاج قيمة واحدة غير NaN على كل جانب من الحدود؛ هنا نستخدم 7 نقاط بيانات
print("quadratic:", s.interpolate(method='quadratic').tolist())
# يناسب منحنياً تربيعياً؛ يتطلب على الأقل 3 نقاط غير NaN
> **المخرجات:** قم بتشغيل هذا في بيئة Python محلية (pandas 2.x). خادم Piston لا يحتوي على مكتبة pandas مثبتة مسبقاً — قم بتثبيتها محلياً (`pip install pandas`) لمتابعة الشرح. قد تتغير القيم الفعلي قليلاً حسب إصدار pandas لديك.
8. النسخ عند الكتابة والعمليات على القيم المفقودة
(1) الكتابة بأمان ضمن نظام النسخ عند الكتابة
▶ مثال
> **الناتج:** قم بتشغيل هذا في بيئة Python محلية (pandas 2.x). خادم Piston لا يحتوي على pandas مثبتًا مسبقًا — قم بتثبيته محليًا (`pip install pandas`) لاتباع المثال. قد تختلف القيم الفعلي قليلاً حسب إصدار pandas لديك.
: عمليات آمنة ضمن نظام النسخ عند الكتابة (الصعوبة ⭐⭐)
import pandas as pd
import numpy as np
pd.options.mode.copy_on_write = True # Pandas 3.x default
df = pd.DataFrame({
'name': ['Alice', 'Bob', 'Charlie'],
'age': [28, np.nan, 25],
'salary': [75000, 92000, np.nan]
})
# ✅ Safe: assign result back
df['age'] = df['age'].fillna(df['age'].mean())
# ✅ Safe: use inplace (works with CoW)
df.fillna({'salary': 0}, inplace=True)
# ❌ Dangerous (pre-CoW): chained assignment
# subset = df[df['age'].notnull()]
# subset['salary'] = 100 # May not modify df!
# ✅ Safe with CoW: loc
df.loc[df['age'].notnull(), 'salary'] = df.loc[df['age'].notnull(), 'salary'] * 1.1
print(df)
> **الناتج:** قم بتشغيل هذا في بيئة Python محلية (pandas 2.x). خادم Piston لا يحتوي على pandas مثبتًا مسبقًا — قم بتثبيته محليًا (`pip install pandas`) لاتباع المثال. قد تختلف القيم الفعلي قليلاً حسب إصدار pandas لديك.
9. مثال شامل: سير العمل الكامل للتعامل مع القيم المفقودة
(5) ▶ شجرة اتخاذ القرار للتعامل مع القيم المفقودة
graph TB
A[Detect missing values] --> B{Missing rate?}
B -->|<5%| C[Drop with dropna]
B -->|5-30%| D{Data type?}
D -->|Numeric| E[fillna with mean/median]
D -->|Categorical| F[fillna with mode]
D -->|Time-series| G[interpolate]
B -->|>50%| H[Consider dropping the column]
> **الخرج:** قم بتشغيل هذا في بيئة بايثون محلية (pandas 2.x). خادم Piston لا يحتوي على مكتبة pandas مثبّتة مسبقًا — قم بتثبيتها محليًا (`pip install pandas`) للمتابعة. قد تختلف القيم الفعليّة قليلًا حسب إصدار pandas لديك.
▶ مثال
> **الخرج:** قم بتشغيل هذا في بيئة بايثون محلية (pandas 2.x). خادم Piston لا يحتوي على مكتبة pandas مثبّتة مسبقًا — قم بتثبيتها محليًا (`pip install pandas`) للمتابعة. قد تختلف القيم الفعليّة قليلًا حسب إصدار pandas لديك.
: سير عمل تنظيف القيم المفقودة الكامل (الصعوبة ⭐⭐⭐)
import pandas as pd
import numpy as np
# ============================================
# Comprehensive example: Full missing-value
# handling pipeline
# ============================================
# 1. Load data with missing values
np.random.seed(42)
df = pd.DataFrame({
'customer_id': range(1, 21),
'name': [f'Customer_{i}' for i in range(1, 21)],
'age': [25, np.nan, 35, 40, np.nan, 28, np.nan, 50, 33, np.nan,
29, np.nan, 45, 38, np.nan, 27, np.nan, 42, 31, np.nan],
'purchase_amount': [120, 85, np.nan, 200, 150, np.nan, 90, 310,
np.nan, 60, 175, np.nan, 250, 140, np.nan,
95, 180, np.nan, 110, 75],
'category': ['Electronics', np.nan, 'Home', 'Electronics', 'Clothing',
'Home', np.nan, 'Electronics', 'Clothing', np.nan',
'Home', 'Electronics', 'Clothing', np.nan, 'Home',
'Electronics', np.nan, 'Home', 'Clothing', 'Electronics']
})
# 2. Analyze missing pattern
print("=== Missing Analysis ===")
missing_report = pd.DataFrame({
'count': df.isnull().sum(),
'pct': (df.isnull().sum() / len(df) * 100).round(1)
})
print(missing_report[missing_report['count'] > 0])
# 3. Drop rows where critical fields are missing
df = df.dropna(subset=['customer_id', 'name'])
# 4. Fill numeric columns
df['age'] = df['age'].fillna(df['age'].median())
df['purchase_amount'] = df['purchase_amount'].interpolate(method='linear')
# 5. Fill categorical column
df['category'] = df['category'].fillna(df['category'].mode()[0])
# 6. Verify: no more missing
print(f"\n=== After Cleaning ===")
print(f"Remaining missing: {df.isnull().sum().sum()}")
print(df.head(10))
> **الخرج:** قم بتشغيل هذا في بيئة بايثون محلية (pandas 2.x). خادم Piston لا يحتوي على مكتبة pandas مثبّتة مسبقًا — قم بتثبيتها محليًا (`pip install pandas`) للمتابعة. قد تختلف القيم الفعليّة قليلًا حسب إصدار pandas لديك.
❓ أسئلة شائعة
df = df.fillna(...), وهو أكثر وضوحاً دلالياً. يضمن وضع CoW أن كلا النهجين ينتجان نفس النتيجة.df['col'].isnull().any() تعيد True/False. للعد: df['col'].isnull().sum() تعيد عدد القيم المفقودة. للنسبة المئوية: df['col'].isnull().mean() * 100. للتحقق من الجدول كاملاً: df.isnull().any().any() تخبرك ما إذا كان DataFrame يحتوي على أي NaN على الإطلاق.df['col'].astype('Int64') (بحرف I كبير), والذي يمثل القيم المفقودة بـ pd.NA مع الحفاظ على دلالات العدد الصحيح.📖 ملخص
- القيمة NaN لا تساوي نفسها (حسب معيار IEEE 754)، لذلك يجب اكتشافها باستخدام الدالة
isnull()— لا يمكن استخدام == - الدوال
isnull/notnullتكتشف القيم المفقودة؛.sum()تقوم بعدها، و.any()تعطي تحققًا سريعًا dropnaتحذف الصفوف/الأعمدة المفقودة:how='any'/'all'، وthreshللعتبة، وsubsetللتحقق من أعمدة محددةfillnaتملأ القيم: ثابت / المتوسط / الوسيط / المنوال؛ في Pandas 2.x استخدمffill()/bfill()بدلاً منmethodinterpolateتملأ بالاستكمال:linearهو الافتراضي،timeتزن بالوقت، وquadratic/cubicتناسب منحنيات- العمليات الآمنة تحت Copy-on-Write: أعد الإسناد إلى متغير أو استخدم
inplace - سير العمل: اكتشف وحلل → احذف ما لا يمكن إصلاحه → املأ/أكمل → تحقق من عدم وجود قيم مفقودة
📝 تمارين
- أساسي (صعوبة ⭐): قم بإنشاء DataFrame يحتوي على NaN. استخدم isnull().sum() لعد القيم المفقودة في كل عمود، ثم احذف الصفوف المفقودة باستخدام dropna()، وقارن التغيير في عدد الصفوف.
- متوسط (صعوبة ⭐⭐): قم بإنشاء DataFrame سلاسل زمنية (10 صفوف مع 3 قيم NaN). قم بملئها باستخدام ffill() / bfill() / interpolate(طريقة='linear') على التوالي، وقارن الاختلافات بين النتائج الثلاثة.
- تحدي (صعوبة ⭐⭐⭐): قم بمحاكاة بيانات 50 عميل (العمر/الراتب/الفئة كل منها مفقود بنسبة 15%) وأنجز سير عمل التنظيف الكامل: تحليل القيم المفقودة → dropna(subset=[أعمدة رئيسية]) → ملء العمر بالمتوسط → الاستيفاء للراتب → ملء الفئة بالوسيط → التحقق من عدم وجود قيم مفقودة.