apply() على الأعمدة والصفوف
استخدم DataFrame.apply() مع axis=0 وaxis=1 لتشغيل دالة مخصصة على كل عمود أو كل صف.
apply() على الأعمدة والصفوف درس مجاني في Pandas & NumPy Academy على CoddyKit. هذا هو الدرس 1 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Pandas & NumPy Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Pandas & NumPy Academy 4 دروس في المجموع.
متى تستخدم apply()
تشغّل DataFrame.apply() دالة Python مخصصة على كل عمود (axis=0) أو كل صف (axis=1). وهي أداة الملاذ الأخير — إذ إنها أبطأ من العمليات المتجهة المضمنة — لكنها ضرورية عندما يتعذر التعبير عن الحساب باستخدام عمليات NumPy الحسابية أو الفهرسة المنطقية أو دوال التجميع المضمنة. استخدمها عند الحاجة إلى منطق شرطي معقد، أو تحليل مخصص للسلاسل النصية، أو حسابات متعددة الخطوات تعمل على صف أو عمود واحد في كل مرة.
import pandas as pd
import numpy as np
df = pd.DataFrame({
'price': [10.5, 25.0, 8.3, 100.0],
'quantity': [3, 1, 5, 2],
'tax_rate': [0.05, 0.10, 0.05, 0.15]
})
print(df)تطبيق apply() على الأعمدة (axis=0)
مع axis=0 (وهو الإعداد الافتراضي)، تمرر apply() كل عمود إلى الدالة على هيئة Series. تستقبل الدالة عمودًا واحدًا في كل مرة، وينبغي أن تعيد قيمة مفردة (للتجميع) أو Series (للتحويل). يفيد ذلك في تطبيق خطوة مخصصة لتوحيد القيم أو تنظيفها بصورة موحّدة على جميع الأعمدة الرقمية في استدعاء واحد.
# Custom range normalisation (0 to 1) for each column
def min_max_scale(col):
return (col - col.min()) / (col.max() - col.min())
df_scaled = df[['price', 'quantity']].apply(min_max_scale, axis=0)
print(df_scaled)تطبيق apply() على الصفوف (axis=1)
مع axis=1، تمرر apply() كل صف إلى الدالة على هيئة Series. ويكون فهرس الصف هو اسم العمود، لذا يمكنك الوصول إلى القيم بالاسم. وهذا مثالي للحسابات على مستوى الصف التي تعتمد على عدة أعمدة، مثل حساب إجمالي الإيرادات بعد الضريبة عندما يكون لكل صف معدل ضريبة خاص به.
def revenue_after_tax(row):
subtotal = row['price'] * row['quantity']
return subtotal * (1 + row['tax_rate'])
df['revenue_after_tax'] = df.apply(revenue_after_tax, axis=1)
print(df)إعادة قيم متعددة باستخدام apply()
يمكن لدالة تُمرَّر إلى apply(axis=1) أن تعيد pd.Series تحتوي على إدخالات مسماة، ويحوّلها Pandas إلى عدة أعمدة جديدة. وهذا أنظف من استدعاء apply() مرتين لإنشاء عمودين جديدين. وبدلًا من ذلك، يمكن للدالة إعادة dict، إذ يحوّله Pandas أيضًا إلى أعمدة.
def compute_totals(row):
subtotal = row['price'] * row['quantity']
tax = subtotal * row['tax_rate']
return pd.Series({'subtotal': subtotal, 'tax': tax, 'total': subtotal + tax})
result = df.apply(compute_totals, axis=1)
print(result)استخدام apply() للتجميع المخصص على الأعمدة
استخدم apply(func, axis=0) لحساب إحصائية مخصصة لكل عمود وإعادة Series تلخيصية. على سبيل المثال، احسب معامل الاختلاف (الانحراف المعياري مقسومًا على المتوسط) لكل عمود رقمي في استدعاء واحد. تكون النتيجة Series مفهرسة بأسماء الأعمدة، وهو ما يفيد في إجراء تشخيصات سريعة لكل عمود.
def coeff_of_variation(col):
return col.std() / col.mean() if col.mean() != 0 else np.nan
cv = df[['price', 'quantity']].apply(coeff_of_variation, axis=0)
print('Coefficient of variation per column:')
print(cv)مقارنة apply() بالبدائل المتجهة
قبل استخدام apply()، تحقّق دائمًا من وجود بديل متجه. فحساب الإيرادات بعد الضريبة، df['price'] * df['quantity'] * (1 + df['tax_rate'])، ينفذ الشيء نفسه الذي تنفذه نسخة apply(axis=1)، لكنه يعمل بسرعة أكبر من 10 إلى 100 مرة لأنه يستخدم حلقات NumPy على مستوى C. خصص استخدام apply() للحالات التي سيصبح فيها المنطق المتجه معقدًا إلى حد يصعب قراءته.
import time
start = time.time()
df['vectorised'] = df['price'] * df['quantity'] * (1 + df['tax_rate'])
print('Vectorised:', time.time() - start, 's')
start = time.time()
df['apply_result'] = df.apply(revenue_after_tax, axis=1)
print('apply():', time.time() - start, 's')استخدام apply() مع Lambda
بالنسبة إلى التحويلات القصيرة المؤلفة من سطر واحد، مرّر lambda مباشرةً إلى apply() بدلًا من تعريف دالة مسماة. تكون Lambdas مختصرة للعمليات البسيطة، لكن ينبغي تجنبها في المنطق المعقد عندما تكون الدالة المسماة المرفقة بالتعليقات أسهل فهمًا واختبارًا. استخدم Lambdas باعتدال؛ إذ يصعب اختبارها وحداتيًا أو تحليل أدائها بالاسم.
# Clip revenue between 0 and 200, then round to nearest 10
df['revenue_clean'] = df['revenue_after_tax'].apply(lambda x: round(min(max(x, 0), 200) / 10) * 10)
print(df[['revenue_after_tax', 'revenue_clean']])تمرير وسيطات إضافية إلى apply()
مرّر الوسيطات الإضافية إلى دالتك باستخدام صف args أو الوسيطات المسماة في apply(func, args=(val,), axis=1). يجنّبك ذلك استخدام المتغيرات العامة داخل الدالة، ويجعلها قابلة لإعادة الاستخدام مع قيم معاملات مختلفة. وفي Python 3.8 والإصدارات الأحدث، يمكنك أيضًا استخدام functools.partial لإنشاء نسخة مطبّقة جزئيًا من الدالة.
def discount_price(row, discount_pct, threshold):
if row['quantity'] >= threshold:
return row['price'] * (1 - discount_pct)
return row['price']
df['discounted_price'] = df.apply(
discount_price, axis=1,
args=(0.1, 3) # 10% discount for quantity >= 3
)
print(df[['price', 'quantity', 'discounted_price']])استخدام apply() لتحويل النوع
عندما يحتوي عمود على أنواع مختلطة — بعض القيم أعداد صحيحة، وبعضها أعداد عشرية، وبعضها سلاسل نصية — تؤدي astype() إلى ظهور خطأ. استخدم apply(pd.to_numeric, errors='coerce') لمحاولة التحويل صفًا تلو الآخر، وإعادة NaN للقيم التي يتعذر تحويلها. يُعد هذا نمطًا آمنًا للأعمدة التي يُفترض أن تكون رقمية لكنها تحتوي أحيانًا على إدخالات غير رقمية بسبب أخطاء إدخال البيانات.
messy = pd.Series(['10', '20.5', 'N/A', '100', '--'])
clean = messy.apply(pd.to_numeric, errors='coerce')
print(clean)الأداء: apply() مقارنةً بـ np.vectorize
عندما يلزم تطبيق دالة تعمل على قيم مفردة على كل عنصر، تكون np.vectorize(func)(array) أسرع عادةً من Series.apply(func)، لأن vectorize في NumPy يمرر الاستدعاءات عبر C بدلًا من تحمل تكلفة استدعاءات الدوال في Python. ومع ذلك، تظل np.vectorize أبطأ من البث الحقيقي؛ لذا لا تُستخدم إلا عندما لا توجد صيغة بث تعبّر عن المنطق.
def classify_size(price):
if price < 15:
return 'small'
elif price < 50:
return 'medium'
return 'large'
# np.vectorize approach
classify_v = np.vectorize(classify_size)
df['size_class'] = classify_v(df['price'].values)
print(df[['price', 'size_class']])متى يكون apply() الخيار المناسب
يكون Apply الأداة المناسبة عندما: (1) يتطلب المنطق اتخاذ فروع بناءً على قيم عدة أعمدة في الوقت نفسه؛ أو (2) تستدعي الدالة واجهة API خارجية أو قاعدة بيانات لكل صف، بحيث يكون التنفيذ المتسلسل أمرًا لا مفر منه؛ أو (3) تحلل الدالة سلسلة نصية معقدة، مثل كائن JSON مخزّن في خلية؛ أو (4) تعيد الدالة كائنًا متغير الطول، مثل قائمة. وفي جميع الحالات الأخرى، فضّل العمليات المتجهة لتحقيق السرعة وسهولة القراءة.
import json
# Parse a JSON metadata column row by row
df['metadata'] = ['{"color": "red"}', '{"color": "blue"}', '{}', '{"color": "green"}']
df['color'] = df['metadata'].apply(lambda s: json.loads(s).get('color', 'unknown'))
print(df[['metadata', 'color']])تحقق سريع
اختبر مدى فهمك لمفاهيم تحليل البيانات التي تناولها هذا الدرس.
مراجعة الدرس
في هذا الدرس تعلّمتُم: استخدام apply(axis=0) لحساب إحصاءات مخصّصة على مستوى الأعمدة، واستخدام apply(axis=1) لإجراء حسابات على مستوى الصفوف باستخدام مدخلات من عدة أعمدة، والتعرّف على الحالات التي يُفضَّل فيها استخدام البدائل المتجهية لتحسين الأداء. بعد ذلك، سنستكشف استخدام apply() مع GroupBy لإجراء عمليات تجميع معقّدة على مستوى المجموعات.
الأسئلة الشائعة
هل درس «apply() على الأعمدة والصفوف» مجاني؟
نعم — نص درس «apply() على الأعمدة والصفوف» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Pandas & NumPy Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Pandas & NumPy Academy 4 دروس في المجموع.
ماذا ستتعلم في «apply() على الأعمدة والصفوف»؟
استخدم DataFrame.apply() مع axis=0 وaxis=1 لتشغيل دالة مخصصة على كل عمود أو كل صف. تتمرن على Pandas & NumPy Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ Pandas & NumPy Academy؟
لا تُشترط خبرة سابقة. Pandas & NumPy Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 1 من أصل 4.
كم من الوقت يستغرق درس «apply() على الأعمدة والصفوف»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس Pandas & NumPy Academy هذا؟
نعم. كل درس في Pandas & NumPy Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- apply() على الأعمدة والصفوف
- apply() مع GroupBy
- map() وapplymap() للعمليات على مستوى العناصر
- تسلسل الأساليب باستخدام pipe()