Machine Learning: معالجة البيانات باستخدام Pandas

آخر تحديث: 2026-08-26

Pandas هو سكين الجيش السويسري لعلوم البيانات — التحميل والتنظيف والتحويل والتجميع، كلها في أداة واحدة.

1. ما ستتعلمه


2. قصة حقيقية من محلل بيانات

(1) نقطة الألم: بيانات CSV فوضوية، والتنظيف يستهلك 80% من الوقت

حصل Bob على بيانات الطلبات الخام من SalesPredict: من أصل 200 ألف سجل، كانت 5% من المبالغ فارغة، و3% طلبات مكررة، وكانت صيغ معرفات المستخدم غير متسقة. بيانات Alice الأمريكية تستخدم أسماء حقول مختلفة عن بيانات Bob، ومبالغ Charlie باليورو تحتاج تحويل عملة. أصبح تنظيف البيانات أكبر مستهلك للوقت في مشروع ML.

(2) حل Pandas

يوفر Pandas سلسلة أدوات كاملة لتنظيف البيانات — معالجة القيم المفقودة، واكتشاف التكرارات، وتحويل الأنواع، ودمج المصادر المتعددة — مما يحوّل تنظيف البيانات من عمل يدوي إلى كود قابل للتكرار.

PYTHON
import pandas as pd

# تحميل وتنظيف في خط أنابيب
df = pd.read_csv("orders.csv")
df_clean = (df
    .drop_duplicates()
    .fillna({"amount": df["amount"].median()})
    .assign(amount_usd=lambda x: x["amount"] * x["exchange_rate"])
)
print(f"Clean rows: {len(df_clean)}, Original: {len(df)}")

(3) النتيجة: انخفض وقت التنظيف من 3 أيام إلى 30 دقيقة

بعد أن قنّن Bob سير عمل تنظيف البيانات باستخدام Pandas، انخفض ما كان يستغرق 3 أيام من التنظيف اليدوي إلى 30 دقيقة من التنفيذ التلقائي — ويمكن إعادة استخدام نفس خط الأنابيب في كل مرة تصل فيها بيانات جديدة.


3. العمليات الأساسية لـ DataFrame و Series

(1) إنشاء DataFrame

PYTHON
import pandas as pd
import numpy as np

# من قاموس
sales_data = pd.DataFrame({
    "date": pd.date_range("2024-01-01", periods=5, freq="D"),
    "category": ["Electronics", "Clothing", "Food", "Books", "Home"],
    "revenue_k_usd": [250, 145, 90, 70, 400],
    "orders": [1200, 800, 3000, 500, 600],
})

# من مصفوفة NumPy
arr = np.random.rand(3, 4)
df_from_arr = pd.DataFrame(arr, columns=["A", "B", "C", "D"])

print(sales_data)
print(f"\nShape: {sales_data.shape}")
print(f"Dtypes:\n{sales_data.dtypes}")

▶ مثال: تحميل بيانات SalesPredict الحقيقية

PYTHON
import pandas as pd

# تحميل CSV مع تلميحات النوع
df = pd.read_csv("sales_data.csv", parse_dates=["order_date"])

# نظرة عامة سريعة
print(f"Shape: {df.shape}")
print(f"\nFirst 5 rows:\n{df.head()}")
print(f"\nData types:\n{df.dtypes}")
print(f"\nMemory usage:\n{df.memory_usage(deep=True)}")

Output:

TEXT 📖 للعرض فقط
# Executed successfully

(2) الاختيار والتصفية

▶ مثال: طرق متعددة لاختيار البيانات

PYTHON
import pandas as pd

df = pd.DataFrame({
    "product": ["Laptop", "Phone", "Tablet", "Monitor", "Keyboard"],
    "category": ["Electronics", "Electronics", "Electronics", "Electronics", "Accessories"],
    "price": [999, 699, 399, 299, 49],
    "stock": [50, 200, 100, 80, 500],
})

# اختيار العمود
prices = df["price"]           # Series
subset = df[["product", "price"]]  # DataFrame

# اختيار الصفوف باستخدام loc (التسمية) و iloc (الموضع)
row = df.loc[0]                # الصف الأول حسب التسمية
rows = df.iloc[1:3]            # الصفوف 1-2 حسب الموضع

# تصفية شرطية
expensive = df[df["price"] > 400]
elec_cheap = df[(df["category"] == "Electronics") & (df["price"] < 500)]

print(f"Expensive items:\n{expensive}")

Output:

TEXT 📖 للعرض فقط
# Executed successfully
طريقة الاختيار الصيغة حالة الاستخدام
اختيار العمود df["col"] / df[["c1","c2"]] الحصول على عمود واحد أو أكثر
loc df.loc[row, col] الفهرسة حسب التسمية
iloc df.iloc[r, c] الفهرسة حسب الموضع
التصفية الشرطية df[df["col"] > val] التصفية بشرط
query df.query("price > 400") تصفية بأسلوب SQL

4. تنظيف البيانات عمليًا

تنظيف البيانات في Pandas هو عملية خط أنابيب — كل خطوة تتعامل مع فئة واحدة من المشاكل، فتحوّل تدريجيًا البيانات المتسخة إلى بيانات نظيفة:

100%
graph LR
    RAW[بيانات خام<br/>5% مفقود, 3% مكرر] --> DEDUP[إزالة التكرارات<br/>drop_duplicates]
    DEDUP --> FILL[ملء القيم المفقودة<br/>fillna median/mode]
    FILL --> OUTLIER[إزالة القيم المتطرفة<br/>IQR clipping]
    OUTLIER --> CONVERT[تحويل النوع<br/>astype / to_datetime]
    CONVERT --> CLEAN[بيانات نظيفة<br/>جاهزة لـ ML]

(1) معالجة القيم المفقودة

▶ مثال: تشخيص ومعالجة القيم المفقودة في SalesPredict

PYTHON
import pandas as pd
import numpy as np

# محاكاة بيانات ذات قيم مفقودة
df = pd.DataFrame({
    "order_id": [1001, 1002, 1003, 1004, 1005, 1006],
    "amount_usd": [150, np.nan, 280, np.nan, 95, 320],
    "category": ["Electronics", "Clothing", np.nan, "Food", "Books", "Electronics"],
    "user_rating": [4.5, 3.8, np.nan, 4.2, np.nan, 5.0],
})

# تشخيص القيم المفقودة
print(f"Missing count:\n{df.isnull().sum()}")
print(f"\nMissing ratio:\n{df.isnull().mean().round(3)}")

# الاستراتيجية 1: حذف الصفوف ذات القيم المفقودة
df_drop = df.dropna()

# الاستراتيجية 2: الملء بالمتوسط/المنوال
df_fill = df.fillna({
    "amount_usd": df["amount_usd"].median(),
    "category": df["category"].mode()[0],
    "user_rating": df["user_rating"].mean(),
})
print(f"\nFilled data:\n{df_fill}")

Output:

TEXT 📖 للعرض فقط
# Executed successfully
الاستراتيجية الطريقة حالة الاستخدام المخاطرة
الحذف dropna() نسبة المفقود < 5% فقدان المعلومات
ملء بالمتوسط fillna(df["col"].mean()) رقمي، طبيعي تقريبًا يقلل التباين
ملء بالوسيط fillna(df["col"].median()) رقمي، ذو قيم متطرفة تقدير محافظ
ملء بالمنوال fillna(df["col"].mode()[0]) فئوي قد يُبالغ في تمثيل الأغلبية
ملء أمامي/خلفي fillna(method="ffill") سلاسل زمنية ينشر الانحياز

(2) التكرارات والقيم المتطرفة

▶ مثال: اكتشاف ومعالجة التكرارات والقيم المتطرفة

PYTHON
import pandas as pd
import numpy as np

df = pd.DataFrame({
    "order_id": [1001, 1002, 1002, 1003, 1004],
    "amount": [150, 280, 280, 95000, 95],
})

# اكتشاف التكرارات
dupes = df.duplicated(subset=["order_id", "amount"])
print(f"Duplicated rows:\n{df[dupes]}")

# إزالة التكرارات
df_clean = df.drop_duplicates(subset=["order_id"], keep="first")

# اكتشاف القيم المتطرفة بطريقة IQR
def detect_outliers_iqr(series, factor=1.5):
    q1, q3 = series.quantile([0.25, 0.75])
    iqr = q3 - q1
    lower, upper = q1 - factor * iqr, q3 + factor * iqr
    return (series < lower) | (series > upper)

outlier_mask = detect_outliers_iqr(df_clean["amount"])
print(f"\nOutliers:\n{df_clean[outlier_mask]}")

# تحديد القيم المتطرفة عند المئين 99
cap = df_clean["amount"].quantile(0.99)
df_capped = df_clean.assign(amount=df_clean["amount"].clip(upper=cap))

Output:

TEXT 📖 للعرض فقط
# Functions defined successfully

5. تحويل البيانات وتجميعها

(1) apply/map/transform

▶ مثال: تحويل الميزات

PYTHON
import pandas as pd

df = pd.DataFrame({
    "product": ["Laptop", "Phone", "Tablet"],
    "price_usd": [999, 699, 399],
    "cost_usd": [600, 350, 180],
})

# map: تحويل عنصر-بعنصر على Series
df["price_level"] = df["price_usd"].map(
    lambda x: "High" if x > 700 else ("Mid" if x > 400 else "Low")
)

# apply: تحويل صف-/عمود-بعنصر
df["margin_pct"] = df.apply(
    lambda row: (row["price_usd"] - row["cost_usd"]) / row["price_usd"] * 100,
    axis=1
)

# transform: مخرجات بنفس الشكل
df["price_zscore"] = df["price_usd"].transform(
    lambda x: (x - x.mean()) / x.std()
)

print(df)

Output:

TEXT 📖 للعرض فقط
# Executed successfully

(2) التجميع حسب المجموعات مع groupby

▶ مثال: تجميع مقاييس المبيعات حسب الفئة

PYTHON
import pandas as pd

df = pd.DataFrame({
    "category": ["Elec", "Elec", "Cloth", "Cloth", "Food", "Food"],
    "month": ["Jan", "Feb", "Jan", "Feb", "Jan", "Feb"],
    "revenue_k": [250, 260, 145, 150, 90, 95],
    "orders": [1200, 1250, 800, 820, 3000, 3100],
})

# تجميع واحد
cat_revenue = df.groupby("category")["revenue_k"].sum()
print(f"Revenue by category:\n{cat_revenue}")

# تجميعات متعددة
cat_stats = df.groupby("category").agg({
    "revenue_k": ["sum", "mean", "std"],
    "orders": ["sum", "mean"],
})
print(f"\nCategory stats:\n{cat_stats}")

# تجميعات مسماة
cat_named = df.groupby("category").agg(
    total_revenue=("revenue_k", "sum"),
    avg_revenue=("revenue_k", "mean"),
    total_orders=("orders", "sum"),
)

Output:

TEXT 📖 للعرض فقط
# Executed successfully

(3) الجداول المحورية مع pivot_table

▶ مثال: جدول محوري للمبيعات الشهرية حسب الفئة

PYTHON
import pandas as pd

df = pd.DataFrame({
    "category": ["Elec"]*3 + ["Cloth"]*3 + ["Food"]*3,
    "month": ["Jan", "Feb", "Mar"]*3,
    "revenue_k": [250, 260, 270, 145, 150, 155, 90, 95, 100],
})

# Pivot: الفئات كصفوف، الأشهر كأعمدة
pivot = df.pivot_table(
    values="revenue_k",
    index="category",
    columns="month",
    aggfunc="sum",
    margins=True,  # إضافة مجاميع الصفوف/الأعمدة
)
print(pivot)

Output:

TEXT 📖 للعرض فقط
# Executed successfully
البُعد groupby pivot_table
شكل المخرجات طويل عريض
مقاييس متعددة ✅ تجميع على أعمدة متعددة ✅ قيم على أعمدة متعددة
المجاميع الفرعية ❌ يتطلب عملًا يدويًا ✅ margins=True
المرونة عالية (أي تجميع) متوسطة (aggfunc ثابت)

6. دمج مصادر بيانات متعددة والسلاسل الزمنية

(1) عمليات الدمج

▶ مثال: دمج بيانات Alice من الولايات المتحدة + بيانات Bob من الصين

PYTHON
import pandas as pd

# طلبات Alice من الولايات المتحدة
us_orders = pd.DataFrame({
    "order_id": ["US001", "US002", "US003"],
    "amount_usd": [150, 280, 95],
    "product": ["Laptop", "Phone", "Book"],
})

# طلبات Bob من الصين (تحتاج تحويل العملة)
cn_orders = pd.DataFrame({
    "order_id": ["CN001", "CN002"],
    "amount_cny": [1200, 3500],
    "product": ["Phone", "Laptop"],
})

# Concat عموديًا (إضافة صفوف)
cn_orders_usd = cn_orders.assign(
    amount_usd=cn_orders["amount_cny"] * 0.14  # CNY إلى USD
).drop(columns=["amount_cny"])
all_orders = pd.concat([us_orders, cn_orders_usd], ignore_index=True)
print(f"Combined orders:\n{all_orders}")

# الدمج مع كتالوج المنتجات
catalog = pd.DataFrame({
    "product": ["Laptop", "Phone", "Book", "Tablet"],
    "category": ["Electronics", "Electronics", "Books", "Electronics"],
    "margin_pct": [35, 45, 20, 30],
})
enriched = all_orders.merge(catalog, on="product", how="left")
print(f"\nEnriched orders:\n{enriched}")

Output:

TEXT 📖 للعرض فقط
# Executed successfully
نوع الدمج الصيغة مكافئ SQL الوصف
داخلي merge(how="inner") INNER JOIN التقاطع
يسار merge(how="left") LEFT JOIN الاحتفاظ بجميع صفوف الجدول الأيسر
خارجي merge(how="outer") FULL JOIN الاتحاد
Concat concat(axis=0) UNION تكديس الصفوف عموديًا
Concat concat(axis=1) تكديس الأعمدة جنبًا إلى جنب

(2) معالجة السلاسل الزمنية

▶ مثال: إعادة العينات والإحصائيات المتدرجة على بيانات SalesPredict اليومية

PYTHON
import pandas as pd
import numpy as np

# بيانات المبيعات اليومية
rng = pd.date_range("2024-01-01", periods=90, freq="D")
daily = pd.DataFrame({
    "date": rng,
    "revenue": np.random.normal(5000, 1000, 90).cumsum(),
}, index=rng)

# إعادة العينة إلى شهرية
monthly = daily["revenue"].resample("M").agg(["first", "last", "mean", "sum"])
print(f"Monthly stats:\n{monthly}")

# نافذة متدرجة: متوسط متحرك 7 أيام
daily["ma_7d"] = daily["revenue"].rolling(window=7).mean()
daily["ma_30d"] = daily["revenue"].rolling(window=30).mean()

# التغيير النسبي
daily["pct_change"] = daily["revenue"].pct_change()

print(f"\nLast 5 rows with rolling stats:\n{daily.tail()}")

Output:

TEXT 📖 للعرض فقط
# Executed successfully

❓ أسئلة شائعة

س ما الفرق بين loc و iloc؟
ج loc يفهرس حسب التسمية ويتضمن نقطة النهاية؛ iloc يفهرس حسب الموضع ويستبعد نقطة النهاية. على سبيل المثال، df.loc[0:3] يُرجع 4 صفوف، بينما df.iloc[0:3] يُرجع 3 صفوف.
س كيف أُصلح تحذير SettingWithCopyWarning؟
ج هذا تحذير من تعيين متسلسل. استخدم .copy() لإنشاء نسخة بشكل صريح، أو استبدل العمليات المتسلسلة بتعيين .loc[] واحد. على سبيل المثال، استخدم df.loc[mask, "col"] = value بدلاً من df[mask]["col"] = value.
س كيف أحتفظ بعمود التجميع كعمود عادي بعد groupby؟
ج استخدم المعامل as_index=False: df.groupby("category", as_index=False).agg(...)، أو استدعِ .reset_index() بعد الـ groupby.
س ماذا لو أنتج merge صفوفًا إضافية غير متوقعة؟
ج تحقق مما إذا كان مفتاح الدمج يحتوي على تكرارات. استخدم df.duplicated(subset=key).sum() للتحقق. إذا كانت هناك تكرارات، حدد استراتيجية الاحتفاظ أولًا (إزالة التكرارات أو التجميع) قبل الدمج.
س ماذا لو نفدت الذاكرة على مجموعة بيانات كبيرة؟
ج ثلاث استراتيجيات: 1) حدد dtypes لتقليل الذاكرة (مثلًا int64 → int32)؛ 2) استخدم المعامل chunksize للقراءة على دفعات؛ 3) استخدم مكتبة Dask لمجموعات البيانات الكبيرة جدًا.
س ماذا لو ألقى المعامل freq خطأً على سلسلة زمنية؟
ج استخدم df.asfreq("D") لضمان تردد منتظم، أو استخدم df.resample("D").asfreq(). تحتاج السلاسل الزمنية غير المنتظمة إلى إعادة عينة قبل التحليل.

📖 ملخص

📝 تمارين

  1. أساسي (الصعوبة ⭐): حمّل ملف CSV، واستخدم info() و describe() للحصول على نظرة عامة، واحسب عدد القيم المفقودة. تلميح: df.isnull().sum().
  2. متوسط (الصعوبة ⭐⭐): أنشئ DataFrame (مبيعات Alice الأمريكية ومبيعات Charlie الأوروبية)، وادمجهما حسب المنتج باستخدام merge، واحسب إجمالي المبيعات العالمية لكل منتج. تلميح: وحّد وحدة المبلغ إلى USD أولًا، ثم ادمج.
  3. تحدي (الصعوبة ⭐⭐⭐): على بيانات المبيعات اليومية، نفّذ: 1) إعادة عينة إلى أسبوعية؛ 2) حساب متوسط متحرك 4 أسابيع؛ 3) اكتشاف القيم المتطرفة (النقاط التي تنحرف أكثر من 2 انحراف معياري عن المتوسط المتدرج). تلميح: resample("W") + rolling(4) + boolean indexing.

← الدرس السابق: دورة مكثفة في NumPy | الدرس التالي: التصور باستخدام Matplotlib و Seaborn →

Web-Tutorial.com

فريق Web-Tutorial التقني

منصة دروس برمجية يديرها عدة مطورين. كل درس يتم كتابته ومراجعته بواسطة مطورين متخصصين في المجال. نعمل على ضمان دقة وموثوقية المحتوى — إذا لاحظت أي مشكلة، فيرجى إخبارنا.

100%