Pandas: تحويل البيانات

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

الخطوة الأخيرة في تنظيف البيانات هي "التحويل" — إعادة تشكيل البيانات الخام إلى الشكل الذي تتطلبه تحليلاتك: تحويل الدرجات إلى تقديرات، والأسعار إلى خصومات، وربط العمليات متعددة الخطوات معًا. توفر أدوات pandas مثل map / apply / pipe / replace / assign / transform مجموعة أدوات تحويل متعددة المستويات تمتد من العناصر الفردية إلى الجداول بأكملها. يتناول هذا القسم حالات الاستخدام والمزالق في الأداء لكل طريقة.

⚠️ ملاحظة: يجب تشغيل الشفرة البرمجية أدناه في بيئة Python محلية.

1. What You Will Learn


2. تحويل درجات أليس

(1) المشكلة: تحويل الدرجات من مقياس 0-100 إلى درجات حرفية ABCD

أليس لديها درجات 100 طالب على مقياس من 0 إلى 100، وتحتاج إلى تحويلها إلى درجات حرفية:

PYTHON
import pandas as pd

scores = pd.DataFrame({
    'name': ['Alice', 'Bob', 'Charlie', 'Carol', 'David'],
    'score': [92, 78, 65, 88, 45]
})
# كيف نحول 0-100 إلى A/B/C/D/F؟
TEXT 📖 للعرض فقط
> **المخرجات:** قم بالتشغيل في بيئة بايثون محلية (pandas 2.x). خادم Piston لا يحتوي على مكتبة pandas مثبتة مسبقاً. يرجى تثبيتها محلياً (`pip install pandas`) والمتابعة. قد تختلف القيم الفعلية قليلاً اعتماداً على إصدار pandas.

(2) الحل: map + التعيين باستخدام القاموس

▶ مثال

TEXT 📖 للعرض فقط
> **المخرجات:** قم بالتشغيل في بيئة بايثون محلية (pandas 2.x). خادم Piston لا يحتوي على مكتبة pandas مثبتة مسبقاً. يرجى تثبيتها محلياً (`pip install pandas`) والمتابعة. قد تختلف القيم الفعلية قليلاً اعتماداً على إصدار pandas.

: map التعيين باستخدام القاموس (صعوبة ⭐)

PYTHON
import pandas as pd

scores = pd.DataFrame({
    'name': ['Alice', 'Bob', 'Charlie', 'Carol', 'David'],
    'score': [92, 78, 65, 88, 45]
})

# الخطوة 1: تعريف دالة تحويل الدرجة إلى درجة حرفية
def score_to_grade(s):
    if s >= 90: return 'A'
    elif s >= 80: return 'B'
    elif s >= 70: return 'C'
    elif s >= 60: return 'D'
    else: return 'F'

# الخطوة 2: تطبيق الدالة باستخدام map
scores['grade'] = scores['score'].map(score_to_grade)
print(scores)
#      name  score grade
# 0   Alice     92     A
# 1     Bob     78     C
# 2 Charlie     65     D
# 3   Carol     88     B
# 4   David     45     F
TEXT 📖 للعرض فقط
> **المخرجات:** قم بالتشغيل في بيئة بايثون محلية (pandas 2.x). خادم Piston لا يحتوي على مكتبة pandas مثبتة مسبقاً. يرجى تثبيتها محلياً (`pip install pandas`) والمتابعة. قد تختلف القيم الفعلية قليلاً اعتماداً على إصدار pandas.

3. تعيين عنصر map

(1) ثلاث طرق لاستخدام map

▶ مثال

TEXT 📖 للعرض فقط
> **Output:** Run in a local Python environment (pandas 2.x). The Piston server does not have pandas pre-installed. Please install it locally (`pip install pandas`) and follow along. Actual values may vary slightly depending on the pandas version.

: ثلاث طرق للتعيين باستخدام map (صعوبة ⭐⭐)

PYTHON
import pandas as pd

s = pd.Series([1, 2, 3, 4, 5])

# 1. Dictionary mapping
category_map = {1: 'Low', 2: 'Low', 3: 'Medium', 4: 'High', 5: 'High'}
print(s.map(category_map))
# 0      Low
# 1      Low
# 2   Medium
# 3     High
# 4     High

# 2. Function mapping
print(s.map(lambda x: x ** 2))
# 0     1
# 1     4
# 2     9
# 3    16
# 4    25

# 3. Series mapping (align by index)
other = pd.Series({1: 'One', 2: 'Two', 3: 'Three'})
print(s.map(other))
# 0    NaN   ← 1 exists in other → 'One'
# 1   Two
# 2 Three
# 3    NaN  ← 4 not in other → NaN
# 4    NaN
TEXT 📖 للعرض فقط
> **Output:** Run in a local Python environment (pandas 2.x). The Piston server does not have pandas pre-installed. Please install it locally (`pip install pandas`) and follow along. Actual values may vary slightly depending on the pandas version.

(2) متى تستخدم map

الميزة map apply
يعمل على عناصر السلسلة الفردية صفوف/أعمدة السلسلة / إطار البيانات
المدخلات قاموس/دالة/سلسلة دالة
الإرجاعات سلسلة (تعيين واحد إلى واحد) أي نوع
الأداء سريع (بحث القاموس O(1)) أبطئ (استدعاءات لكل عنصر/صف/عمود)
الأفضل لـ تعيين واحد إلى واحد منطق معقد/عمليات متعددة الأعمدة

4. تطبيق دوال الصفوف/الأعمدة

(1) تطبيق Series (السلسلة)

▶ مثال

TEXT 📖 للعرض فقط
> **الناتج:** قم بالتشغيل في بيئة بايثون محلية (pandas 2.x). لا يحتوي خادم Pandas على مكتبة pandas مثبتة مسبقاً. يرجى تثبيتها محلياً (`pip install pandas`) والمتابعة. قد تختلف القيم الفعليهة قليلاً حسب إصدار pandas.

: تطبيق Series (الصعوبة ⭐⭐)

PYTHON
import pandas as pd

s = pd.Series(['alice@example.com', 'bob@company.org', 'charlie@uni.edu'])

# استخراج النطاق من البريد الإلكتروني
domains = s.apply(lambda email: email.split('@')[1])
print(domains)
# 0    example.com
# 1    company.org
# 2       uni.edu

# منطق معقد: تصنيف نوع البريد الإلكتروني
def classify_email(email):
    domain = email.split('@')[1]
    if '.edu' in domain: return 'Academic'
    elif '.org' in domain: return 'Non-profit'
    else: return 'Commercial'

email_type = s.apply(classify_email)
print(email_type)
# 0    Commercial
# 1    Non-profit
# 2     Academic
TEXT 📖 للعرض فقط
> **الناتج:** قم بالتشغيل في بيئة بايثون محلية (pandas 2.x). لا يحتوي خادم Pandas على مكتبة pandas مثبتة مسبقاً. يرجى تثبيتها محلياً (`pip install pandas`) والمتابعة. قد تختلف القيم الفعليهة قليلاً حسب إصدار pandas.

(2) تطبيق DataFrame (إطار البيانات)

▶ مثال

TEXT 📖 للعرض فقط
> **الناتج:** قم بالتشغيل في بيئة بايثون محلية (pandas 2.x). لا يحتوي خادم Pandas على مكتبة pandas مثبتة مسبقاً. يرجى تثبيتها محلياً (`pip install pandas`) والمتابعة. قد تختلف القيم الفعليهة قليلاً حسب إصدار pandas.

: تطبيق عمليات الصفوف/الأعمدة على DataFrame (الصعوبة ⭐⭐)

PYTHON
import pandas as pd
import numpy as np

df = pd.DataFrame({
    'math': [85, 92, 78, 88, 65],
    'english': [90, 85, 82, 75, 70],
    'science': [88, 95, 80, 90, 60]
}, index=['Alice', 'Bob', 'Charlie', 'Carol', 'David'])

# تطبيق الدالة على كل عمود (axis=0، الافتراضي)
print(df.apply(np.mean))
# math       81.6
# english    80.4
# science    82.6

# تطبيق الدالة على كل صف (axis=1)
df['average'] = df.apply(lambda row: row.mean(), axis=1)
print(df['average'])
# Alice      87.67
# Bob        90.67
# Charlie    80.00
# Carol      84.33
# David      65.00

# إرجاع Series لكل صف (أكثر تنظيمًا)
def score_report(row):
    return pd.Series({
        'total': row.sum(),
        'avg': row.mean(),
        'max': row.max(),
        'min': row.min()
    })

report = df[['math', 'english', 'science']].apply(score_report, axis=1)
print(report)
TEXT 📖 للعرض فقط
> **الناتج:** قم بالتشغيل في بيئة بايثون محلية (pandas 2.x). لا يحتوي خادم Pandas على مكتبة pandas مثبتة مسبقاً. يرجى تثبيتها محلياً (`pip install pandas`) والمتابعة. قد تختلف القيم الفعليهة قليلاً حسب إصدار pandas.
⚠️ ملاحظة: apply ليست عملية متوجهة (vectorized) — استدعاء دالة صفًا بصف على DataFrame كبير سيكون بطيئًا جدًا. إذا كنت قادرًا على استخدام العمليات المتوجهة (العمليات الحسابية، طرق str)، فلا تستخدم apply. apply هي "الملاذ الأخير عندما لا يعمل أي شيء آخر."


5. تسلسل الأنابيب (pipe Chaining)

(1) تدفق البيانات المتسلسل

▶ مثال

TEXT 📖 للعرض فقط
> **الخرج:** شغّل في بيئة Python محلية (pandas 2.x). خادم Piston لا يحتوي على pandas مثبتة مسبقاً. يرجى تثبيتها محلياً (`pip install pandas`) والاتباع. القيم الفعلية قد تختلف قليلاً حسب إصدار pandas.

: عمليات خط أنابيب (الصعوبة ⭐⭐)

PYTHON
import pandas as pd
import numpy as np

# Raw data
df = pd.DataFrame({
    'name': ['  Alice  ', 'BOB', 'Charlie', '  carol  ', 'David'],
    'age': [28, -1, 25, 30, 999],
    'salary': [75000, np.nan, 68000, 88000, np.nan]
})

# Step-by-step without pipe (nested calls)
# result = assign_dept(replace_invalid(clean_names(df)))

# With pipe — readable left-to-right flow
def clean_names(df):
    df = df.copy()
    df['name'] = df['name'].str.strip().str.title()
    return df

def replace_invalid(df):
    df = df.copy()
    df.loc[df['age'] < 0, 'age'] = np.nan
    df.loc[df['age'] > 150, 'age'] = np.nan
    return df

def fill_salary(df):
    df = df.copy()
    df['salary'] = df['salary'].fillna(df['salary'].median())
    return df

result = (df
    .pipe(clean_names)
    .pipe(replace_invalid)
    .pipe(fill_salary)
)
print(result)
TEXT 📖 للعرض فقط
> **الخرج:** شغّل في بيئة Python محلية (pandas 2.x). خادم Piston لا يحتوي على pandas مثبتة مسبقاً. يرجى تثبيتها محلياً (`pip install pandas`) والاتباع. القيم الفعلية قد تختلف قليلاً حسب إصدار pandas.

(2) مقارنة بين pipe و apply

الميزة pipe apply
المدخلات إطار البيانات بالكامل صف/عمود/سلسلة
الإرجاع إطار بيانات (محوّل) أي نوع
الغرض خط أنابيب متعدد الخطوات عمليات عنصر/صف/عمود من خطوة واحدة
التسلسل ✅ مدعوم بشكل أصلي ❌ يتطلب التداخل
سهولة القراءة عالية (تقرأ من الأعلى إلى الأسفل) متوسطة

6. استبدال القيمة

(1) الاستبدال الدقيق

▶ مثال

TEXT 📖 للعرض فقط
> **Output:** Run in a local Python environment (pandas 2.x). The Piston server does not have pandas pre-installed. Please install it locally (`pip install pandas`) and follow along. Actual values may vary slightly depending on the pandas version.

: استبدال القيمة (الصعوبة ⭐)

PYTHON
import pandas as pd
import numpy as np

df = pd.DataFrame({
    'status': ['active', 'inactive', 'pending', 'active', 'unknown'],
    'priority': [1, 2, 3, 1, 99]
})

# Single value replacement
df['status'] = df['status'].replace('unknown', 'inactive')
print(df['status'])

# Multiple values replacement (dict)
df['status'] = df['status'].replace({
    'active': 'Active',
    'inactive': 'Inactive',
    'pending': 'Pending'
})
print(df['status'])

# Replace invalid sentinel value
df['priority'] = df['priority'].replace(99, np.nan)
print(df['priority'])

# Regex replacement
text = pd.Series(['Phone: 555-0100', 'Email: test@example.com'])
cleaned = text.str.replace(r'[\d-]+', '[REDACTED]', regex=True)
print(cleaned)
TEXT 📖 للعرض فقط
> **Output:** Run in a local Python environment (pandas 2.x). The Piston server does not have pandas pre-installed. Please install it locally (`pip install pandas`) and follow along. Actual values may vary slightly depending on the pandas version.

(2) مقارنة replace و map

الميزة replace map
القيم غير المطابقة تبقى دون تغيير تصبح NaN
استبدال قيم متعددة ✅ قاموس ✅ قاموس
Regex ✅ regex=True
الأنسب لـ استبدال قيم محددة تعيين كامل
🔥 خطأ شائع: القيم غير المشمولة بالقاموس في map ستصبح NaN! في replace، القيم غير المشمولة تبقى دون تغيير. إذا أردت "استبدال قيم قليلة فقط والاحتفاظ بالباقي"، استخدم replace. إذا أردت "تعيينًا كاملًا حيث يتم تجاهل القيم غير المعينة"، استخدم map.


7. تعيين أعمدة جديدة

(1) ربط أعمدة جديدة متعددة

▶ مثال

TEXT 📖 للعرض فقط
> **الإخراج:** قم بالتشغيل في بيئة Python محلية (pandas 2.x). لا تحتوي خادم Pandas على pandas مثبته مسبقاً. يرجى تثبيتها محلياً (`pip install pandas`) واتباع الخطوات. قد تختلف القيم الفعلية قليلاً حسب إصدار pandas.

: تعيين أعمدة جديدة (الصعوبة ⭐⭐)

PYTHON
import pandas as pd

df = pd.DataFrame({
    'price': [100, 200, 150, 80, 300],
    'quantity': [5, 3, 10, 8, 2],
    'discount': [0.1, 0.2, 0.0, 0.15, 0.05]
})

# Add multiple columns in one chain
result = (df
    .assign(
        discounted_price=lambda x: x['price'] * (1 - x['discount']),
        total=lambda x: x['discounted_price'] * x['quantity'],
        is_bulk=lambda x: x['quantity'] >= 5
    )
)
print(result)
#   price  quantity  discount  discounted_price  total  is_bulk
# 0   100         5      0.10              90.0  450.0     True
# 1   200         3      0.20             160.0  480.0    False
# 2   150        10      0.00             150.0 1500.0     True
# 3    80         8      0.15              68.0  544.0     True
# 4   300         2      0.05             285.0  570.0    False
TEXT 📖 للعرض فقط
> **الإخراج:** قم بالتشغيل في بيئة Python محلية (pandas 2.x). لا تحتوي خادم Pandas على pandas مثبته مسبقاً. يرجى تثبيتها محلياً (`pip install pandas`) واتباع الخطوات. قد تختلف القيم الفعلية قليلاً حسب إصدار pandas.
💡 نصيحة: داخل assign، استخدم lambda x: للإشارة إلى DataFrame الحالية. يمكنك الإشارة إلى أعمدة تم إنشاؤها مسبقاً ضمن نفس استدعاء assign (على سبيل المثال، total تشير إلى discounted_price). هذا يجعله أكثر ملاءمة للربط مقارنةً بنص df['new_col'] = ....


8. تحويل المجموعة باستخدام transform

(1) transform يحافظ على الشكل الأصلي

▶ مثال

TEXT 📖 للعرض فقط
> **Output:** Run in a local Python environment (pandas 2.x). The Piston server does not have pandas pre-installed. Please install it locally (`pip install pandas`) and follow along. Actual values may vary slightly depending on the pandas version.

: معايرونة المجموعة باستخدام transform (الصعوبة ⭐⭐)

PYTHON
import pandas as pd
import numpy as np

df = pd.DataFrame({
    'student': ['Alice', 'Alice', 'Bob', 'Bob', 'Charlie', 'Charlie'],
    'subject': ['Math', 'English', 'Math', 'English', 'Math', 'English'],
    'score': [85, 90, 92, 88, 78, 82]
})

# Z-score normalization within each student
df['z_score'] = df.groupby('student')['score'].transform(
    lambda x: (x - x.mean()) / x.std()
)
print(df)

# Fill with group mean (instead of global mean)
df['score_filled'] = df.groupby('student')['score'].transform('mean')
print(df[['student', 'score', 'score_filled']])

# Rank within group
df['rank_in_class'] = df.groupby('subject')['score'].transform('rank', method='min')
print(df[['student', 'subject', 'score', 'rank_in_class']])
TEXT 📖 للعرض فقط
> **Output:** Run in a local Python environment (pandas 2.x). The Piston server does not have pandas pre-installed. Please install it locally (`pip install pandas`) and follow along. Actual values may vary slightly depending on the pandas version.

(2) مقارنة transform و apply

الميزة transform apply
شكل الإخراج نفس الإدخال يمكن أن يتغير
بعد groupby يعيد نتائج بنفس الطول لكل مجموعة يعيد أي نتيجة لكل مجموعة
التجميع ❌ لا يمكن التجميع ✅ يمكن
البث ✅ يبث تلقائياً إلى الصفوف الأصلية
الاستخدامات الشائعة المعايرونة/الملء/الترتيب التجميع/الحسابات المعقدة

9. اختيار طريقة التحويل المناسبة

(1) مرجع سريع لـ 6 طرق تحويل

100%
graph TB
    Q["هل تحتاج لتحويل البيانات؟"] --> TYPE{"نوع التحويل؟"}
    TYPE -->|"تعيين واحد إلى واحد"| MAP["map()"]
    TYPE -->|"دالة على صف/عمود"| APPLY["apply()"]
    TYPE -->|"خط خطوات متعدد"| PIPE["pipe()"]
    TYPE -->|"استبدال قيم محددة"| REPLACE["replace()"]
    TYPE -->|"إضافة أعمدة جديدة"| ASSIGN["assign()"]
    TYPE -->|"تحويل على مستوى المجموعة"| TRANS["transform()"]
    MAP --> NOTE1["✅ قاموس/دالة<br>❌ غير مُعيّن ← NaN"]
    APPLY --> NOTE2["⚠️ بطيء لإطارات البيانات الكبيرة<br>✅ مرن"]
    PIPE --> NOTE3["✅ سلسلة قابلة للقراءة<br>✅ خطوات قابلة لإعادة الاستخدام"]
    REPLACE --> NOTE4["✅ القيم غير المتطابقة محفوظة<br>✅ يدعم التعبيرات النمطية"]
    ASSIGN --> NOTE5["✅ صديق للسلاسل<br>✅ أعمدة متعددة"]
    TRANS --> NOTE6["✅ ناتج بنفس الشكل<br>✅ بث للمجموعة"]
TEXT 📖 للعرض فقط
> **الناتج:** قم بالتشغيل في بيئة Python محلية (pandas 2.x). خادم Piston لا يحتوي على pandas مثبّتًا مسبقًا. يرجى تثبيته محليًا (`pip install pandas`) والمتابعة. قد تختلف القيم الفعلي قليلاً حسب إصدار pandas.

(2) ترتيب الأداء

الترتيب الطريقة الأداء السبب
1 العمليات المُتجسدة الأسرع تنفيذ على مستوى C، بدون حلقة بايثون
2 map (قاموس) سريع بحث O(1)
3 replace سريع مُحسّن داخليًا
4 map (دالة) متوسط استدعاءات دوال لكل عنصر
5 apply بطيء استدعاءات بايثون لكل صف/عمود
6 apply + منطق معقد الأبطأ تراكم تكلفة الدوال
💡 نصيحة: إذا كنت تستطيع كتابة df['col'] * 2، فلا تكتب df['col'].apply(lambda x: x * 2). العمليات المُتجسدة أسرع بـ 10-100 مرة من apply.


10. مثال كامل: خط تحويل بيانات التجارة الإلكترونية

▶ مثال

TEXT 📖 للعرض فقط
> **Output:** Run in a local Python environment (pandas 2.x). The Piston server does not have pandas pre-installed. Please install it locally (`pip install pandas`) and follow along. Actual values may vary slightly depending on the pandas version.

: خط تحويل بيانات كامل (الصعوبة ⭐⭐⭐)

PYTHON
import pandas as pd
import numpy as np

# ============================================
# مثال شامل: تحويل بيانات التجارة
# الإلكترونية
# ============================================

# 1. البيانات الخام
np.random.seed(42)
df = pd.DataFrame({
    'product': [f'Item_{i:03d}' for i in range(1, 21)],
    'category': np.random.choice(['Electronics', 'Clothing', 'Home'], 20),
    'price': np.round(np.random.uniform(10, 500, 20), 2),
    'cost': np.round(np.random.uniform(5, 250, 20), 2),
    'quantity_sold': np.random.randint(1, 100, 20),
    'rating': np.round(np.random.uniform(2.0, 5.0, 20), 1)
})

# 2. خط معالجة خطوة بخطوة باستخدام pipe
def add_margin(df):
    df = df.copy()
    df['margin_pct'] = ((df['price'] - df['cost']) / df['price'] * 100).round(1)
    return df

def categorize_price(df):
    df = df.copy()
    df['price_tier'] = df['price'].map(
        lambda p: 'Budget' if p < 50 else ('Mid' if p < 200 else 'Premium')
    )
    return df

def add_revenue(df):
    return df.assign(
        revenue=lambda x: x['price'] * x['quantity_sold'],
        is_top_rated=lambda x: x['rating'] >= 4.0
    )

def normalize_rating(df):
    df = df.copy()
    df['rating_zscore'] = df.groupby('category')['rating'].transform(
        lambda x: (x - x.mean()) / x.std()
    )
    return df

# 3. تنفيذ الخط
result = (df
    .pipe(add_margin)
    .pipe(categorize_price)
    .pipe(add_revenue)
    .pipe(normalize_rating)
)

# 4. ملخص
print("=== Transformation Result ===")
print(result[['product', 'category', 'price_tier', 'margin_pct', 'revenue', 'is_top_rated']].head(10))
print(f"\nTotal revenue: ${result['revenue'].sum():,.2f}")
print(f"Top-rated items: {result['is_top_rated'].sum()}")
print(f"Price tier distribution:\n{result['price_tier'].value_counts()}")
TEXT 📖 للعرض فقط
> **الخرج:** قم بالتشغيل في بيئة بايثون محلية (pandas 2.x). خادم Piston لا يحتوي على مكتبة pandas مثبته مسبقاً. يرجى تثبيتها محلياً (`pip install pandas`) والمتابعة. القيم الفعلية قد تختلف قليلاً حسب إصدار pandas.

❓ أسئلة شائعة

س ما الفرق بين map و apply؟
ج تعمل map فقط على Series، وتُجري عملية تعيين واحد لواحد على كل عنصر (تقبل قاموسًا أو دالة). تصبح القيم غير المُعيَّنة NaN. تعمل apply على كل من Series و DataFrame، وتدعم عمليات على مستوى الصف/العمود (axis=0/1) بأنواع إرجاع مرنة. استخدم map للتعيينات البسيطة (أسرع)، و apply للمنطق المعقد (مرن أكثر).
س لماذا apply بطيئة؟
ج apply هي في جوهرها حلقة Python — تستدعي دالة Python مرة واحدة لكل صف/عمود، وتكلفة استدعاء الدالة ضخمة. العمليات المُشتَّتة (vectorized) تُنفَّذ على مستوى C دون هذه التكلفة. قاعدة عامة: إذا كنت تستطيع كتابة df['a'] + df['b']، فلا تكتب df.apply(lambda r: r['a']+r['b'], axis=1). apply هي الملاذ الأخير.
س ما الفرق بين pipe و apply؟
ج تعمل pipe على DataFrame بالكامل، وتقبل DataFrame وتعيد DataFrame — وهي مصممة لخطوط أنابيب متعددة الخطوات. تعمل apply على الصفوف/الأعمدة/Series لحساب لكل عنصر أو لكل صف. قيمة pipe تكمن في الوضوح — فتحول f3(f2(f1(df))) إلى df.pipe(f1).pipe(f2).pipe(f3)، حيث يمنحك القراءة من أعلى إلى أسفل ترتيب التنفيذ.
س ما الفرق بين replace و map؟
ج أكبر اختلاف هو كيفية تعاملهما مع القيم غير المتطابقة — يحتفظ replace بالقيمة الأصلية دون تغيير، بينما تحوّل map القيم غير المتطابقة إلى NaN. استخدم replace عندما تريد فقط استبدال بعض القيم المحددة؛ استخدم map للتعيين الكامل حيث يجب تحويل كل قيمة. يدعم replace أيضًا الاستبدال بالتعبيرات النمطية (regex=True)، وهو ما لا تدعمه map.
س ما الفرق بين assign و df['col']=...؟
ج يُرجع assign DataFrame جديدًا (بدون تعديل الأصل)، مما يجعله مثاليًا للتسلسل. df['col']=... يُعدّل الأصل مباشرة. داخل assign، يمكنك استخدام lambda للإشارة إلى أعمدة تم إنشاظها في نفس الخطوة، وهو ما لا يمكن للإسناد المباشر فعله. التوصية: استخدم assign للعمليات المتسلسلة؛ في الحالات البسيطة، الإسناد المباشر مقبول.
س ما الفرق بين transform و apply بعد groupby؟
ج تُرجع transform نتيجة بنفس طول DataFrame الأصلي (بث داخل كل مجموعة)، بينما يمكن أن تُرجع apply أي شكل. على سبيل المثال: groupby + transform('mean') يُرجع متوسط المجموعة لكل صف (الطول دون تغيير)، بينما groupby + apply('mean') يُرجع متوسطًا واحدًا لكل مجموعة (الطول = عدد المجموعات). استخدم transform للحفاظ على الشكل الأصلي؛ استخدم apply/agg للتجميع.
س ما معنى "مُشتَّتة" (vectorized) بالضبط؟
ج التشتيت (Vectorization) يعني استخدام العمليات المدمجة في Pandas/NumPy بدلاً من حلقات Python. df['a'] + df['b'] هي عملية مُشتَّتة (حساب على مستوى C عبر المصفوفة بأكملها)، بينما df.apply(lambda r: r['a']+r['b'], axis=1) ليست كذلك (استدعاءات Python صفًا بصف). العمليات المُشتَّتة أسرع بـ 10-100 مرة. استخدم العمليات المدمجة كلما أمكن بدلاً من apply.

📖 ملخص


📝 تمارين

  1. أساسي (صعوبة ⭐): أنشئ سلسلة (Series) للدرجات (0-100). استخدم map مع قاموس لتصنيف الدرجات إلى عالية (≥70)/متوسطة (≥50)/منخفضة (<50)، ثم استخدم replace لتغيير "متوسطة" إلى "متوسط".
  2. متوسط (صعوبة ⭐⭐): أنشئ إطار بيانات (DataFrame) للموظفين (الاسم/الراتب/القسم). استخدم pipe لبناء خط أنابيب من 3 خطوات: تنظيف الاسم (strip+title) → إضافة عمود للراتب بعد الضريبة → تحديد ما إذا كان كل موظف يكسب أكثر من متوسط قسمه.
  3. تحدي (صعوبة ⭐⭐⭐): أنشئ مجموعة بيانات منتجات تحتوي على 20 صفًا. استخدم assign لإضافة 3 أعمدة دفعة واحدة (الإيرادات/الهامش/الفئة)، استخدم groupby+transform لحساب الدرجات المعيارية (z-scores) داخل كل فئة، وأخيرًا استخدم pipe لدمج جميع الخطوات في خط أنابيب واحد.

← Previous: Handling Duplicate Data · Next: Group Aggregation →

Web-Tutorial.com

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

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

100%