0Pricing
Pandas & NumPy Academy · درس

تسلسل الأساليب باستخدام pipe()

اكتب مسارات تحويل بيانات سهلة القراءة باستخدام pipe() لتسلسل الدوال المخصصة إلى جانب أساليب Pandas الأصلية.

تسلسل الأساليب باستخدام pipe() درس مجاني في Pandas & NumPy Academy على CoddyKit. هذا هو الدرس 4 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Pandas & NumPy Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Pandas & NumPy Academy 4 دروس في المجموع.

مشكلة المتغيرات الوسيطة

غالبًا ما تتراكم في مسار تنظيف البيانات الذي لا يستخدم pipe() متغيرات وسيطة كثيرة: df1 = clean(df)، وdf2 = transform(df1)، وdf3 = enrich(df2). تؤدي هذه المتغيرات إلى ازدحام مساحة الأسماء، وتصعّب تصحيح الأخطاء، وتغري المطوّرين بإعادة استخدامها بطريقة غير صحيحة. والنتيجة شيفرة يصعب قراءتها من الأعلى إلى الأسفل باعتبارها سلسلة من التحويلات.

import pandas as pd

df = pd.read_csv('orders.csv')

# Without pipe — intermediate variables everywhere
df1 = df.dropna(subset=['revenue'])
df2 = df1[df1['quantity'] > 0]
df3 = df2.assign(revenue_per_unit=df2['revenue'] / df2['quantity'])
print(df3.shape)

التعرّف على pipe()

تستدعي DataFrame.pipe(func) الدالة func(df) وتُرجع النتيجة، مما يتيح لكم تسلسل الدوال المخصّصة بالطريقة نفسها التي تسلسلون بها أساليب Pandas الأصلية مثل .dropna().query(). وتتمثل الفائدة الأساسية في أن كل خطوة تحويل تكون واضحة وسهلة القراءة من اليسار إلى اليمين، أو من الأعلى إلى الأسفل عند تنسيقها باستخدام الأقواس، بما يعكس الترتيب المنطقي للمسار.

def drop_nulls(df):
    return df.dropna(subset=['revenue'])

def filter_positive_qty(df):
    return df[df['quantity'] > 0]

def add_revenue_per_unit(df):
    return df.assign(revenue_per_unit=df['revenue'] / df['quantity'])

# With pipe — clean chain
df_clean = (df
    .pipe(drop_nulls)
    .pipe(filter_positive_qty)
    .pipe(add_revenue_per_unit)
)
print(df_clean.shape)

تمرير الوسائط عبر pipe()

مرّروا الوسائط الإضافية إلى الدالة التي يمر عبرها المسار باستخدام وسائط الكلمات المفتاحية بعد اسم الدالة: df.pipe(func, arg1=val1). ويجب أن يتيح توقيع الدالة استقبال df باعتباره المعامل الأول. تجعل الدوال ذات المعاملات المسار قابلًا للتهيئة؛ إذ يمكنكم تغيير الحدود أو أسماء الأعمدة أو السلوك دون تعديل جسم الدالة، وذلك بتغيير وسائط استدعاء pipe فقط.

def filter_by_region(df, regions):
    return df[df['region'].isin(regions)]

def cap_revenue(df, upper):
    df = df.copy()
    df['revenue'] = df['revenue'].clip(upper=upper)
    return df

df_result = (df
    .pipe(filter_by_region, regions=['North', 'East'])
    .pipe(cap_revenue, upper=1000)
)
print(df_result.shape)

دمج pipe() مع الأساليب الأصلية

تكمن قوة pipe() في تكامله بسلاسة مع أساليب Pandas الأصلية ضمن السلسلة نفسها. يمكنكم مزج .dropna() و.query() و.rename() و.pipe(custom_func) بأي ترتيب. وهذا يجعل السلسلة موجزة (باستخدام الأساليب المضمّنة حيثما أمكن) ومرنة في الوقت نفسه (باستخدام الدوال المخصّصة عندما لا تكفي الأساليب المضمّنة).

df_result = (
    df
    .dropna(subset=['revenue', 'order_date'])
    .query('quantity > 0')
    .rename(columns={'unit_price': 'price'})
    .pipe(add_revenue_per_unit)
    .reset_index(drop=True)
)
print(df_result.head())

تصحيح أخطاء سلسلة pipe()

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

def debug(df, label=''):
    print(f'[{label}] shape: {df.shape}')
    print(f'[{label}] columns: {df.columns.tolist()}')
    return df

df_result = (
    df
    .pipe(drop_nulls)
    .pipe(debug, label='after drop_nulls')
    .pipe(filter_positive_qty)
    .pipe(debug, label='after filter')
)
print('Done')

إنشاء مسار تنظيف متكامل

اجمعوا جميع خطوات التنظيف في دالة مسار واحدة باستخدام pipe(). إن تغليف السلسلة داخل دالة باسم clean_pipeline(df) يجعل اختبار المسار كوحدة واحدة أمرًا ممكنًا. استدعوا الدالة باستخدام DataFrame خام لتحصلوا على DataFrame نظيف. يتوافق هذا النمط مع نموذج ETL (الاستخراج والتحويل والتحميل) المستخدم في هندسة البيانات في بيئات الإنتاج.

def clean_pipeline(df):
    return (
        df
        .dropna(subset=['order_id', 'revenue'])
        .drop_duplicates(subset=['order_id'])
        .query('quantity > 0 and revenue >= 0')
        .pipe(add_revenue_per_unit)
        .reset_index(drop=True)
    )

df_clean = clean_pipeline(df)
print('Clean rows:', len(df_clean))

الاختلافات الرئيسية بين pipe() و apply()

يمرر pipe(func) إطار DataFrame بأكمله إلى func، ويتوقع استعادة DataFrame (أو كائن محوّل). أما apply(func, axis=1) فيمرر صفًا واحدًا في كل مرة. استخدموا pipe() لتحويلات DataFrame بالكامل التي تحافظ على الشكل نفسه (أو تغيّره عمدًا)، واستخدموا apply() للحسابات على مستوى الصفوف أو الأعمدة. فهما متكاملان وليس أحدهما بديلًا عن الآخر.

# pipe: receives the whole DataFrame
def scale_revenue(df, factor=1.0):
    df = df.copy()
    df['revenue'] = df['revenue'] * factor
    return df

# apply: receives one row at a time
df['revenue_x2'] = df.apply(lambda row: row['revenue'] * 2, axis=1)

df_scaled = df.pipe(scale_revenue, factor=1.1)
print('pipe scales all rows at once; apply does row-by-row')

مكوّنات المسار القابلة لإعادة الاستخدام

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

def normalise_strings(df, cols):
    df = df.copy()
    for col in cols:
        df[col] = df[col].str.strip().str.lower()
    return df

def parse_dates(df, cols):
    df = df.copy()
    for col in cols:
        df[col] = pd.to_datetime(df[col])
    return df

df_result = (
    df
    .pipe(normalise_strings, cols=['region', 'category'])
    .pipe(parse_dates, cols=['order_date'])
)
print(df_result.dtypes)

تسجيل خطوات المسار باستخدام pipe()

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

import logging
logging.basicConfig(level=logging.INFO)

def logged_dropna(df, subset):
    before = len(df)
    df = df.dropna(subset=subset)
    after = len(df)
    logging.info(f'dropna: {before - after} rows removed, {after} remaining')
    return df

df_clean = df.pipe(logged_dropna, subset=['revenue'])
print('Logged pipeline complete.')

الخطوات الشرطية في المسار

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

def maybe_cap_revenue(df, cap=None):
    if cap is None:
        return df
    df = df.copy()
    df['revenue'] = df['revenue'].clip(upper=cap)
    return df

CAPPING_ENABLED = True
CAP_VALUE = 1000 if CAPPING_ENABLED else None

df_result = df.pipe(maybe_cap_revenue, cap=CAP_VALUE)
print('Conditional step applied:', CAPPING_ENABLED)

تصدير نتيجة المسار

غالبًا ما تكون الخطوة الأخيرة في سلسلة pipe() هي التصدير. يمكنكم ربط دالة تصدير مخصّصة باستخدام pipe()، أو استدعاء أسلوب التصدير الأصلي في Pandas بعد السلسلة ببساطة. ويؤدي استخدام خطوة pipe(save_to_parquet) إلى إبقاء جزء التصدير موثقًا ضمن السلسلة، وضمان تشغيله دائمًا على DataFrame النهائي المنظّف، لا على نسخة وسيطة.

def save_parquet(df, path):
    df.to_parquet(path, index=False)
    print(f'Saved {len(df)} rows to {path}')
    return df  # return df so the chain can continue if needed

df_final = (
    df
    .pipe(clean_pipeline)
    .pipe(save_parquet, path='orders_final.parquet')
)
print('Pipeline complete.')

تحقق سريع

اختبروا مدى فهمكم لمفاهيم تحليل البيانات التي تناولها هذا الدرس.

مراجعة الدرس

تعلمتم في هذا الدرس: استخدام pipe() لربط الدوال المخصّصة بأساليب Pandas الأصلية، وإنشاء خطوات مسار قابلة لإعادة الاستخدام ومعلمة وقابلة للاختبار بوصفها دوال نقية، وإضافة تسجيلات التصحيح والخطوات الشرطية داخل سلسلة pipe. نستكشف لاحقًا تنظيم خطوات التحويل في صورة دوال لمسار ETL مخصص لبيئة الإنتاج.

الأسئلة الشائعة

هل درس «تسلسل الأساليب باستخدام pipe()» مجاني؟

نعم — نص درس «تسلسل الأساليب باستخدام pipe()» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Pandas & NumPy Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Pandas & NumPy Academy 4 دروس في المجموع.

ماذا ستتعلم في «تسلسل الأساليب باستخدام pipe()»؟

اكتب مسارات تحويل بيانات سهلة القراءة باستخدام pipe() لتسلسل الدوال المخصصة إلى جانب أساليب Pandas الأصلية. تتمرن على Pandas & NumPy Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ Pandas & NumPy Academy؟

لا تُشترط خبرة سابقة. Pandas & NumPy Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 4 من أصل 4.

كم من الوقت يستغرق درس «تسلسل الأساليب باستخدام pipe()»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس Pandas & NumPy Academy هذا؟

نعم. كل درس في Pandas & NumPy Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. ‏apply() على الأعمدة والصفوف
  2. ‏apply() مع GroupBy
  3. ‏map() وapplymap() للعمليات على مستوى العناصر
  4. تسلسل الأساليب باستخدام pipe()
← العودة إلى Pandas & NumPy Academy