الربط حسب الفهرس
استخدم DataFrame.join() واضبط left_index/right_index=True في merge() لدمج DataFrame المتحاذية حسب فهرسها.
الربط حسب الفهرس درس مجاني في Pandas & NumPy Academy على CoddyKit. هذا هو الدرس 4 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Pandas & NumPy Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Pandas & NumPy Academy 4 دروس في المجموع.
عمليات الربط المستندة إلى الفهرس
حتى الآن، دمجتم DataFrames من خلال مطابقة القيم في الأعمدة العادية. لكن المعلومات التي تريدون المطابقة بناءً عليها تكون أحيانًا مخزنة في فهرس DataFrame بدلًا من عمود. يدعم Pandas عمليات الربط المستندة إلى الفهرس من خلال DataFrame.join()، وكذلك من خلال pd.merge() باستخدام المعاملين left_index=True أو right_index=True.
الطريقة DataFrame.join()
DataFrame.join(other) طريقة مساعدة تنفّذ الربط باستخدام فهرس كلا DataFrame افتراضيًا. وهي مكافئة لاستدعاء pd.merge() باستخدام left_index=True, right_index=True. ويكون نوع الربط الافتراضي هو 'left'، على خلاف pd.merge() الذي يكون افتراضيه 'inner'. يجب أن يشترك كلا DataFrame في تسميات فهرس ذات معنى حتى ينتج الربط نتائج صحيحة.
import pandas as pd
profiles = pd.DataFrame(
{'age': [25, 30, 22]},
index=['alice', 'bob', 'carol']
)
scores = pd.DataFrame(
{'score': [88, 95, 70]},
index=['alice', 'carol', 'dave']
)
# join: left join on index (default)
result = profiles.join(scores)
print(result)
# age score
# alice 25 88.0
# bob 30 NaN <- bob has no score
# carol 22 95.0التحكم في نوع الربط باستخدام join()
مرّر المعامل how إلى join() للتحكم في الصفوف التي يتم الاحتفاظ بها، كما هو الحال مع pd.merge(). الخيارات هي 'left' (الافتراضي)، و'right'، و'inner'، و'outer'. على سبيل المثال، يحتفظ how='inner' بالفهارس الموجودة في كلا إطاري البيانات فقط، ويحذف صف alice إذا لم يكن له فهرس مطابق في الجدول الأيمن.
# Inner join on index: only rows present in BOTH indices
print(profiles.join(scores, how='inner'))
# age score
# alice 25 88
# carol 22 70
# Outer join: all indices from both
print(profiles.join(scores, how='outer'))
# age score
# alice 25.0 88.0
# bob 30.0 NaN
# carol 22.0 70.0
# dave NaN 95.0ضم عدة إطارات بيانات في آنٍ واحد
من أهم مزايا join() مقارنةً بـ pd.merge() أنه يقبل قائمة من إطارات البيانات، ويضمّها جميعًا إلى الإطار المستدعي باستدعاء واحد. يجب أن تكون جميع إطارات البيانات متوافقة في الفهارس. يكون ذلك ملائمًا جدًا عند وجود العديد من جداول الميزات المفهرسة بالمفتاح نفسه، مثل معرّف المستخدم أو التاريخ، والرغبة في تجميعها في إطار بيانات عريض واحد.
emails = pd.DataFrame({'email': ['a@x.com', 'b@x.com', 'c@x.com']},
index=['alice', 'bob', 'carol'])
city = pd.DataFrame({'city': ['NY', 'LA', 'SF']},
index=['alice', 'bob', 'carol'])
# Join multiple DataFrames at once
result = profiles.join([emails, city])
print(result)
# age email city
# alice 25 a@x.com NY
# bob 30 b@x.com LA
# carol 22 c@x.com SFالضم باستخدام عمود في أحد الجدولين وفهرس في الآخر
يتيح pd.merge() الجمع بين المطابقة القائمة على الأعمدة والمطابقة القائمة على الفهارس باستخدام left_on/right_index أو left_index/right_on. يكون ذلك مفيدًا عندما يخزّن أحد إطاري البيانات المفتاح في عمود، بينما يستخدمه الآخر فهرسًا. لا يمكن تحقيق ذلك باستخدام join() وحده.
# orders has customer_id as a column; customers is indexed by customer_id
customers_indexed = pd.DataFrame(
{'name': ['Alice', 'Bob', 'Carol']},
index=[101, 102, 103]
)
orders = pd.DataFrame({
'order_id': [1, 2, 3],
'customer_id': [101, 102, 101]
})
result = pd.merge(orders, customers_indexed,
left_on='customer_id', right_index=True)
print(result)
# order_id customer_id name
# 0 1 101 Alice
# 2 3 101 Alice
# 1 2 102 Bobاستخدام left_index و right_index في merge()
عندما يكون المفتاح فهرسًا في كلا إطاري البيانات، استخدم pd.merge(left, right, left_index=True, right_index=True). وهذا يكافئ join()، لكنه يستخدم نوع الضم الافتراضي 'inner' ومعاملات أكثر وضوحًا. كما تحصل على إمكانية استخدام جميع معاملات pd.merge() الأخرى، مثل suffixes وindicator.
# Both DataFrames indexed by user_id
demog = pd.DataFrame({'age': [25, 30]}, index=[1, 2])
behav = pd.DataFrame({'clicks': [10, 5]}, index=[1, 2])
# Equivalent joins
result1 = demog.join(behav) # left join
result2 = pd.merge(demog, behav, left_index=True, right_index=True) # inner join
print(result1)
print(result2)لماذا نستخدم عمليات الضم القائمة على الفهرس؟
يُفضَّل استخدام عمليات الضم القائمة على الفهرس عندما تكون إطارات البيانات مرتبطة طبيعيًا بمعرّف ذي معنى، مثل معرّف المستخدم أو SKU المنتج أو التاريخ. يؤدي استخدام الفهرس في عمليات الضم إلى تجنّب إضافة أعمدة مفاتيح مكررة إلى إطار البيانات، وقد يكون أسرع لأن Pandas تحتفظ ببنى فهارس مرتبة تتيح البحث بزمن O(log n). وتشيع هذه العمليات خصوصًا في بيانات السلاسل الزمنية، حيث يكون DatetimeIndex هو مفتاح الضم الطبيعي.
# Time series example: join temperature and humidity by date index
import numpy as np
dates = pd.date_range('2024-01-01', periods=5)
temp = pd.DataFrame({'temp_c': [10, 12, 9, 11, 13]}, index=dates)
humid = pd.DataFrame({'humidity': [65, 70, 60, 75, 68]}, index=dates)
weather = temp.join(humid)
print(weather.head())التعامل مع أسماء الأعمدة المتداخلة
عندما يحتوي كلا إطاري البيانات على أعمدة بالاسم نفسه (باستثناء المفتاح)، يرفع join() استثناء ValueError افتراضيًا ما لم توفّر المعاملين lsuffix وrsuffix. يعمل هذان المعاملان مثل suffixes في pd.merge()، إذ يُلحقان سلسلة نصية بأسماء الأعمدة المتداخلة في إطاري البيانات الأيسر والأيمن على التوالي.
df_a = pd.DataFrame({'value': [1, 2]}, index=['x', 'y'])
df_b = pd.DataFrame({'value': [10, 20]}, index=['x', 'y'])
# Without suffixes: raises ValueError
# result = df_a.join(df_b)
# With suffixes: disambiguate column names
result = df_a.join(df_b, lsuffix='_left', rsuffix='_right')
print(result)
# value_left value_right
# x 1 10
# y 2 20set_index قبل الضم
من الأساليب الشائعة تعيين عمود ليصبح فهرسًا قبل إجراء عملية الضم، حتى تتمكن من استخدام صياغة join(). بعد الضم، يعيد reset_index() المفتاحَ كعمود عادي. يعبّر هذا النمط عن الخطوات بوضوح: ترقية المفتاح إلى فهرس، ثم إجراء الضم، ثم إعادة المفتاح إلى عمود، مما يوضّح المقصود لقرّاء الشيفرة لاحقًا.
orders_col = pd.DataFrame({'order_id': [1,2,3], 'customer_id': [10,20,10], 'amount': [100,200,150]})
cust_col = pd.DataFrame({'customer_id': [10,20], 'name': ['Alice','Bob']})
result = (
orders_col.set_index('customer_id')
.join(cust_col.set_index('customer_id'), how='left')
.reset_index()
)
print(result)محاذاة Series مع فهرس إطار بيانات
يمتلك Series فهرسًا أيضًا، ويمكنك إضافته كعمود جديد إلى إطار بيانات باستخدام الإسناد؛ إذ تحاذي Pandas قيم Series تلقائيًا مع تسميات الفهرس المطابقة. وهذه صورة خفيفة من الضم القائم على الفهرس، وتناسب الحالات التي تريد فيها إضافة عمود واحد من Series من دون استدعاء merge() أو join().
df = pd.DataFrame({'sales': [100, 200, 150]}, index=['A', 'B', 'C'])
tax_rate = pd.Series({'A': 0.1, 'B': 0.2, 'C': 0.15})
# Index alignment: Series aligns to DataFrame index automatically
df['tax'] = df['sales'] * tax_rate
print(df)
# sales tax
# A 100 10.0
# B 200 40.0
# C 150 22.5أداء الضم باستخدام الفهرس
يكون الضم باستخدام فهرس مرتب أسرع من الضم باستخدام عمود عادي، لأن Pandas تستخدم البحث الثنائي على الفهرس المرتب. إذا كنت تجري عمليات ضم متكررة باستخدام المفتاح نفسه، فعيّن ذلك المفتاح فهرسًا مرة واحدة في بداية مسار المعالجة. وتكتسب هذه الخطوة أهمية خاصة في مسارات عمل السلاسل الزمنية، حيث تجري عمليات الضم باستخدام DatetimeIndex آلاف المرات عبر العديد من الملفات.
# Sort index before repeated joins for speed
left = left.sort_index()
right = right.sort_index()
# Both sorted -> Pandas uses merge path with binary search
result = left.join(right, how='inner')
# Check if index is sorted
print('Left sorted:', left.index.is_monotonic_increasing)
print('Right sorted:', right.index.is_monotonic_increasing)تحقق سريع
اختبر مدى فهمك لعمليات الضم القائمة على الفهرس من هذا الدرس.
مراجعة الدرس
تعلّمت في هذا الدرس أن DataFrame.join() يجري الضم باستخدام الفهرس افتراضيًا مع ضم أيسر؛ وأن pd.merge() مع left_index=True/right_index=True يوفّر تحكمًا أكبر؛ وأنه يمكنك ضم عدة إطارات بيانات في آنٍ واحد بتمرير قائمة إلى join()؛ وأن استخدام فهرس مرتب يحسّن أداء الضم. بعد ذلك، سنستكشف إعادة تشكيل إطارات البيانات باستخدام pivot_table.
الأسئلة الشائعة
هل درس «الربط حسب الفهرس» مجاني؟
نعم — نص درس «الربط حسب الفهرس» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Pandas & NumPy Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Pandas & NumPy Academy 4 دروس في المجموع.
ماذا ستتعلم في «الربط حسب الفهرس»؟
استخدم DataFrame.join() واضبط left_index/right_index=True في merge() لدمج DataFrame المتحاذية حسب فهرسها. تتمرن على Pandas & NumPy Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ Pandas & NumPy Academy؟
لا تُشترط خبرة سابقة. Pandas & NumPy Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 4 من أصل 4.
كم من الوقت يستغرق درس «الربط حسب الفهرس»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس Pandas & NumPy Academy هذا؟
نعم. كل درس في Pandas & NumPy Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- pd.concat لتكديس DataFrame
- pd.merge: عمليات الربط الداخلي والخارجي
- عمليات الربط اليسرى واليمنى
- الربط حسب الفهرس